CharSequence per rappresentare un oggetto con nome

3

Ho sempre seguito l'opinione di non abusare delle interfacce in caso di decomposizione. Di solito li realizzo solo se sono assolutamente sicuro di avere una relazione "is-a" ed evito di implementarli se c'è un legame "ha-a" con un altro tipo di oggetto.

Ora, questa etica mi porta a un problema: Sto scrivendo una piccola libreria che include un tipo che contiene una proprietà "nome". Gli oggetti che rappresentano questo tipo sono creati quasi esclusivamente attraverso un file XML dove sono definiti. L'idea di dare un nome a quegli oggetti è di accedervi facilmente nel codice.

La definizione assomiglia a questa:

<root>
    <object name="foo">
    ....
    </object>
</root>

Nel codice dovrebbe essere possibile applicare qualsiasi rappresentatore di questo tipo per nome o per oggetto stesso. Quindi il tipo include un nome:

public interface NamedObject {

    String getName();

    .....
}

Quindi ora i seguenti due esempi dovrebbero creare lo stesso risultato:

Esempio 1:

NamedObject obj = Utils.getFromXML("obj_name");
Foo.doStuff(obj);

Esempio 2:

Foo.doStuff("obj_name");

Il motivo per cui questo dovrebbe funzionare è che potrebbe esserci un contesto in cui il programmatore sta già lavorando con un oggetto così chiamato e quindi dovrebbe essere in grado di usarlo direttamente come nell'esempio 1. Ma potrebbe esserci un contesto in cui desidera chiamare un metodo che dipende da tale oggetto e il programmatore potrebbe voler utilizzare un oggetto con nome definito nell'XML. Quindi poteva solo cercare il nome e usarlo tramite il suo nome.

Il vero problema è che questo mi sta portando a un pasticcio nella mia progettazione strutturale poiché ci sono molti oggetti che richiedono questo tipo di oggetti nei loro metodi e nella maggior parte dei casi c'è anche un comportamento predefinito definito.

Quindi se c'è un comportamento predefinito ho bisogno di 3 implementazioni del metodo.

public interface Bar {

    void doStuff()

    void doStuff(String namedObjectName);

    void doStuff(NamedObject object);
}

Quindi, per esempio, 6 funzionalità potrebbero portare a 18 metodi.

Penso che non ci potrebbe essere un altro modo per rappresentare il comportamento predefinito di fornire un metodo senza parametro. Potrei eseguire il comportamento predefinito accettando i puntatori nulli ed eseguire il comportamento predefinito se viene fornito un puntatore nullo ma, ai miei occhi, un metodo param-less è la soluzione più carina.

Quindi per sbarazzarsi di una delle altre due firme il NamedObject -type potrebbe ereditare da java.lang.CharSequence . Le implementazioni dei metodi di java.lang.CharSequence possono essere eseguite usando la proprietà name. Dal momento che Java 8 potevo già implementarli di default nell'interfaccia usando il metodo getName() .

Con questa mossa potrei sostituire il metodo accettando il parametro java.lang.String che rappresenta il nome e il metodo che accetta NamedObject con un singolo metodo che accetta un java.lang.CharSequence che rappresenta il nome o l'oggetto stesso.

Il NamedObject -type stesso CLEARLY DOES NON rappresenta una relazione "is-a" al suo nome. Rappresenta una relazione "ha-a".

E questa è la domanda. Qual è il modo migliore per progettare una biblioteca che includa una tale struttura? La mia intenzione è ok?

    
posta narranoid 07.09.2015 - 09:58
fonte

1 risposta

4

L'ereditarietà di java.lang.CharSequence probabilmente ti causerà molti più problemi di manutenzione in futuro, non solo a causa del problema tecnico di has-a / is-a.

Penso che il vero problema è che stai provando a supportare chiamate come questa direttamente:

  Foo.doStuff("obj_name");

In questo modo, la tua classe Foo deve essere accoppiata a Utils.getFromXML , il che lo rende probabilmente più complesso di quanto dovrebbe essere. Ignoriamo per un momento la parte "comportamento predefinito" della tua domanda. Quindi ti consiglio di progettare la tua interfaccia in questo modo:

public interface Bar {
    void doStuff(NamedObject object);
}

e se ti serve, fornisci un helper o una classe di utilità XmlUtil contenente una funzione come questa

public void DoStuff(Bar bar, String objname)
{
    NamedObject obj = Utils.getFromXML(objname);
    bar.DoStuff(obj);
}

Quindi puoi chiamarlo come

XmlUtil.DoStuff(Foo, "obj-name");

che è solo un po 'più lungo della tua chiamata originale, ma rende esplicito il contesto Xml.

In questo modo, non devi fornire lo stesso mapping "stringa - > oggetto" in ogni implementazione Bar più e più volte, puoi riutilizzare la funzione sopra per qualsiasi implementazione Bar . Inoltre, solo la tua classe di utilità ora deve essere accoppiata direttamente all'Xml, non alle tue 'implementazioni Bar'.

    
risposta data 07.09.2015 - 10:38
fonte

Leggi altre domande sui tag