Evitare l'implementazione di molti ruoli nello stesso oggetto

1

Motivazione

Lascia un progetto in cui ...

... esiste un comportamento molto diverso. Per ogni comportamento, c'è un'interfaccia che ha le sue possibili azioni. Un oggetto potrebbe comportarsi in modo molto diverso.

Normalmente, un collaboratore "A" si preoccupa solo dell'interfaccia "I" di un oggetto specifico.

Quindi, come evitare che un oggetto implementi molti ruoli.

Esempio:

public class MyComplexObject implements Closeable, Reliable, Trustable, Treable, Moveable { ...}

Perché preoccuparsi?

Composition risolve il problema. Ma solo parzialmente. In Java, l'oggetto di destinazione dovrà ancora delegare le chiamate ai problemi per l'implementazione di destinazione. Sebbene sia un'implementazione senza cervello, non è comodo quando l'elenco dei ruoli è superiore a 5.

L'ereditarietà (oltre le interfacce) non migliorerà le cose.

Supponiamo 6 diverse interfacce (ogni interfaccia con 5 metodi). Per ora, semplificiamo e immaginiamo un'implementazione predefinita per queste interfacce. Ora, supponiamo che un insieme di oggetti più complessi possa implementare da una a sei di queste interfacce. Significa 2 ^ 6 = 64 diverse combinazioni possibili. Inoltre, una lunga lista di interfacce significa una lunga lista di metodi interni.

È chiaro che l'ereditarietà, utilizzando una BaseImplementation, non ha senso in questo caso.

Esempi:

public class MyComplexObject1 implements Closeable, Reliable, Trustable, Treable, Moveable { ...}
public class MyComplexObject2 implements Reliable, Treable, Moveable { ...}
public class MyComplexObject3 implements Reliable, Trustable, Moveable { ...}
public class MyComplexObject4 implements Closeable, Trustable, Treable { ...}

Non sto chiedendo un proiettile d'argento

"Essere scettici", "evitare la complessità", naturalmente, quelle cose vanno bene. Tuttavia, troppo generale. Questo problema si verifica quando una lunga lista di ruoli fa male. Quindi questo è uno scenario d'angolo e non un problema mainstream.

Cosa non significa scenario non realistico. C'è un progetto che usa un'idea che potrebbe essere usata per risolvere quel problema.

Netbeans, che ha il concetto di cookie

EditorCookie ec = activatedNodes[0].getLookup().lookup(EditorCookie.class);

A cookie is a capability and cookies are a powerful feature of NetBeans. With a Java interface, your object's capabilities are fixed at compile time, while NetBeans cookies allow your object to behave dynamically because your object can expose capabilities, or not, based on its state.

link

Come implementare i cookie

public class MyComplexObject { 
    private Map<Class<?>, ?> adapters;

    public <T> T getAdapterIfApplicable(Class<T> t){
       return (T) adapters.get(t);
    }
    public MyComplexObject add(Class<T> aClass, T t){
       adapters(aClass, t);
       t.setTarget(this);
    }
...
}
...
public CloseableAdapter implements Adapter{
    void setTarget(Object target){
        this.target = target; 
    }
}
...
new MyComplexObject().add(CloseableAdapter.class, aCloseAdapter);    
    
posta rdllopes 26.05.2015 - 20:22
fonte

1 risposta

9

Dai commenti e dalle modifiche emerge che la tua preoccupazione riguarda più la duplicazione del codice in più classi di implementazione. Questo ha niente da fare con quante interfacce sono implementate.

Pattern composito con delega

Se le implementazioni di ogni interfaccia sono generiche, dovrebbero essere classi a cui è stato delegato l'utilizzo di Composite Pattern. Il modello dell'adattatore non è la soluzione in entrambi i casi.

Se A implements C allora A è un C . Appesantire il codice chiamante con questa offuscazione di Adapter Pattern è una decisione terribile dell'API.

La domanda che stai ponendo non è quella giusta:

... come evitare che un oggetto implementi un lungo elenco di interfacce.

Penso che tu stia vedendo un problema che esiste solo per te. Ho lavorato su centinaia di milioni di righe di codice Java dal 1995. Non ho mai visto il problema di cui ti sembra preoccupato.

Il numero di combinazioni di interfacce non è un problema pratico. Non è mai stato. Se hai troppe interfacce con molti metodi, allora questo è un problema di progettazione che deve essere risolto, la tua soluzione non è quella correzione .

Stai aggiungendo una quantità ridicola di complessità senza alcun evidente vantaggio:

implements significa che cosa sta implementando quell'interfaccia è una relazione , che è abbastanza strettamente accoppiata e l'introduzione di Adapter tipo di pattern indiretto sta andando a gonfiare il codebase con più complessità e codice da mantenere e test, che è una ragione sufficiente per non farlo.

Se questo fosse un buon approccio sarebbe stato fatto una mezza dozzina di volte come una libreria opensource dei 20 anni in cui Java è stato in giro.

Questo modello di adattatore che stai tentando di utilizzare non è l'approccio corretto, creerà un'API pesante e onerosa e sarà estremamente fragile.

Il lavoro per utilizzare l'API sarà uno sforzo di ordine di grandezza maggiore del mantenimento di codice ingenuamente duplicato.

    
risposta data 27.05.2015 - 00:31
fonte

Leggi altre domande sui tag