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?