Refactoring di una classe astratta esistente e dei suoi parametri

8

Ho un abstract class A che dichiara un metodo astratto doStuff . Attualmente ci sono molte classi che ereditano da A e implementano doStuff .

Le istanze della classe 'sono inizializzate in fase di esecuzione tramite AFactory in base all'input dell'utente. Originariamente tutte le classi avevano lo stesso parametro singolo (l'input dell'utente). Ma ora ho un parametro aggiuntivo che richiede solo una nuova classe che eredita A .

Quindi analizzandoli, ho pensato alla seguente logica:

  • La classe interprete che genera istanze basate sull'input dell'utente (utilizzando AFactory ovviamente) non era a conoscenza di questo parametro extra.

    • Cercare di spingerlo nella classe degli interpreti di classe sarebbe davvero imbarazzante, perché poi dovrei sapere quando passare alla fabbrica che sconfigge l'intero scopo di avere una fabbrica in primo luogo.
    • L'invio ciecamente alla Factory sperando che possa fare qualcosa con esso sembra abbastanza brutto.
  • La mia soluzione corrente: nel frattempo ho deciso di ridefinire A.doStuff(Param param) in A.doStuff(AParams params) .

    AParams può contenere tutti i parametri necessari e doStuff può ignorare se non sono interessati a loro. Anche questo mi sembra un po 'imbarazzante e mi rimuove l'invio di strutture in WIN32API che possono contenere molti parametri inutili e non mi piacciono molto.

C'è un modo più elegante per affrontare questo problema? O qualche schema di progettazione che ho trascurato e risolvo questo?

Note :

  • Utilizziamo Java 1.7
  • I nomi delle classi sono sciocchi per enfatizzare il problema di progettazione teorico che hanno nomi indicativi e significativi nella realtà:)
  • Ho cercato molto ma ho capito che è piuttosto difficile cercare sul web specifiche questioni teoriche astratte (a differenza di perché X lancia Exception in questo codice) ho deciso di chiedere comunque quindi mi dispiace se questo è un duplicato.

Modifica 1 :

  • Precisazione: ho bisogno di passare un argomento specifico per sottoclasse al metodo doStuff .

EDIT 2 :

  • Non ho compreso appieno l'intenzione di Kilian Foth, quindi ho scritto qualche pseudo-codice Java per aiutarmi a spiegare meglio il problema / capire la tua soluzione. Quindi:

    Questo è uno scheletro del mio problema.

    Questo è uno scheletro della mia soluzione.

    Questo è ciò che penso potrebbe essere la soluzione di Kilian Foth, ma non ne sono sicuro.

posta Scis 30.04.2013 - 10:15
fonte

3 risposte

9

Il punto di una fabbrica è quello di nascondere il fatto che è possibile ottenere oggetti da classi leggermente diverse. Pertanto, se alcuni di questi oggetti necessitano di determinati dati e altri no ...

  • O non sono abbastanza simili per essere prodotti dalla stessa fabbrica. Quindi è necessario avere più di una fabbrica e prendere la decisione prima di quanto si sta facendo attualmente.

  • O sono sono abbastanza simili a quelli che il cliente non dovrebbe preoccuparsi di quello che ricevono. Quindi non puoi aspettarti che il cliente si preoccupi se inviare o meno i dati extra. Ne consegue che devono passare sempre , ma a volte la fabbrica li ignorerà senza preoccuparsi del client con i dettagli di implementazione. Qualunque altra cosa avrebbe onorato il cliente con la stessa distinzione che la fabbrica avrebbe dovuto nascondere.

risposta data 30.04.2013 - 10:36
fonte
2

Lo gestisco utilizzando qualcosa come Builder che contiene varie fabbriche. Il Builder ha degli hash che contengono le fabbriche per creare vari tipi di oggetti, e guarderà nell'hash e recupererà il factory corretto in base a qualsiasi criterio.

Ad esempio, ho più tipi di domande, e tutte queste possono essere fatte da alcune implementazioni di un IQuestionFactory. La maggior parte delle implementazioni di IQuestionFactory sono sottoclassi di BaseQuestionFactory e ricevono XML che rappresenta una domanda e la analizzano in base alle regole della domanda, restituendo una sottoclasse di BaseQuestion.

Alcune domande richiedono più informazioni, ad esempio se si tratta di una domanda di compilazione di moduli, potrebbe esserci una sezione dell'XML che contiene le domande che definiscono i campi utilizzati nel modulo. Le fabbriche che fanno queste domande implementano IEnhancedQuestionFactory e il builder controllerà la Factory che recupera da QuestionFactoryRegistry e verifica se implementa questa interfaccia. Se lo fa, passa l'XML completo del file che conteneva le domande oltre al singolo XML che va al metodo createQuestion.

Per mostrarti quanto può essere flessibile, alcune delle implementazioni di IQuestionFactory sono semplicemente shell che contengono più fabbriche di domande, e possono guardare il codice XML in entrata e quindi chiamare una factory interna e restituire qualsiasi cosa faccia. Lo usiamo quando un file XML contiene più tipi di domande.

Tuttavia, sembra che tu abbia bisogno di qualcosa di più del modo in cui costruiamo Esercizi (che sono essenzialmente Controllori avvolti attorno a una serie di Domande), dove l'hash (ExerciseFactoryMap) è impostato per restituire una fabbrica predefinita per la maggior parte del tempo, ma nei casi in cui ha una specifica fabbrica registrata, la restituirà. E abbiamo una Factory specifica che creerà una sottoclasse Exercise con una proprietà aggiuntiva, e ha la capacità aggiuntiva di guardare l'XML e trovare le informazioni di cui ha bisogno per popolare quella proprietà.

Quindi, sono d'accordo con Killian Foth che il punto di a factory è di nascondere i dettagli dell'implementazione di come viene costruito l'oggetto, ma non c'è nulla che dice che non è possibile combinare più Factory in modo creativo (ad esempio, una Factory che contiene altre Fabbriche che fanno il vero lavoro).

    
risposta data 30.04.2013 - 16:59
fonte
2
  • Il solito approccio in casi come questo (Command patternish) sta passando parametri aggiuntivi nel costruttore. Nel tuo caso, ciò significa aggiungere otherArgument a B durante la costruzione.

  • Girare la logica potrebbe aprire alcune opzioni. Ad esempio spostando doStuff in AParams:

    for (String arg : listOfArgs) {
        AParams p = AParams.create(arg, otherArgument));
        for (A a : listOfA) {
            p.doStuff(a); // Let AParams to the lifting depending on type of A
        }
    }
    
  • In alternativa puoi ingoiare il tuo orgoglio e controllare con instanceof nel ciclo e impostare otherArgument manualmente prima di chiamare doStuff .

Se quanto sopra non è possibile, non hai altra scelta che fare quello che stai facendo (allargando l'argomento dei parametri). Non analizzare troppo questa roba.

    
risposta data 01.05.2013 - 08:13
fonte

Leggi altre domande sui tag