L'idea stessa è valida. Ma non funzionerà, se si rende il pacchetto root root (qui: NumberSet
) privato. Esporre questo tipo o utilizzare invece un'interfaccia pubblica. I veri tipi di implementazione dovrebbero (e possono) essere nascosti.
public abstract class NumberSet {
// Constructor is package private, so no new classes can be derived from
// this guy outside of its package.
NumberSet() {
}
}
public class Factories {
public NumberSet range(int start, int length) {
return new RangeNumberSet(start, length);
}
// ...
}
class RangeNumberSet extends NumberSet {
// ... must be defined in the same package as NumberSet
// Is "invisible" to client code
}
Modifica Per esporre un tipo di nascosto/privato radice da un'API pubblica è un errore. Si consideri il seguente scenario:
package example;
class Bar {
public void doSomething() {
// ...
}
}
public class Foo {
public Bar newBar() {
return new Bar();
}
}
e considerare un'applicazione client che utilizza questa API. Cosa può fare il cliente? Non può dichiarare correttamente una variabile per avere il tipo Bar
poiché quel tipo è invisibile a qualsiasi classe esterna al pacchetto example
. Non può nemmeno chiamare i metodi public
su un'istanza Bar
che ha ricevuto da qualche parte, poiché non sa, che un tale metodo pubblico esiste (non può vedere la classe, per non parlare dei membri che espone). Quindi, il meglio che un cliente può fare è qualcosa del tipo:
Object bar = foo.newBar();
che è essenzialmente inutile. Una cosa diversa sarebbe avere un'interfaccia pubblica (o una classe astratta) al posto del pacchetto privato, come nel codice sopra definito. In questo caso, il cliente in realtà può dichiarare una variabile di tipo NumberSet
. Non può creare le proprie istanze o derivare sottoclassi, poiché il costruttore è nascosto da esso, ma può accedere all'API pubblica definita.
modificare nuovamente Anche se si desidera un valore di "informe" (dal punto di vista del cliente), vale a dire, un valore, che non definisce alcun API interessanti il cliente può decidere di chiamare, è ancora una buona idea esporre un tipo di base pubblica nel modo descritto sopra. E sia per il solo scopo che il compilatore sia in grado di eseguire il controllo di tipo e che consenta al codice client di memorizzare temporaneamente tale valore in una variabile (dichiarata correttamente).
Se non si desidera che il client chiami alcun metodo API sul tipo: va bene. Non c'è nulla che ti impedisce di non fornire un'API pubblica sul tuo (altrimenti) tipo di base pubblico. Basta non dichiararne nessuno. Utilizzare una classe di base astratta "vuota" (vuota dal punto di vista del client, poiché tutti i metodi interessanti sarebbero pacchetti privati e quindi nascosti). Tuttavia, è necessario fornire un tipo di base pubblico, oppure è necessario utilizzare il valore Object
come valore di ritorno, ma in tal caso si perde il controllo degli errori in fase di compilazione.
Regola generale: se il cliente deve chiamare un metodo in modo da ottenere un valore e passare a qualche altro API, il client in realtà sa, che ci sono alcuni valori speciali magici. E deve essere in grado di gestirlo in qualche modo ("passarlo avanti", almeno). Non fornire un tipo corretto per il client per gestire i valori non ti compra nulla tranne per gli avvisi del compilatore (del tutto appropriato).
public abstract class Specification {
Specification() {
// Package private, thus not accessible to the client
// No subclassing possible
}
Stuff getInternalValue1() {
// Package private, thus not accessible to the client
// Client cannot call this
}
}
La classe precedente è "vuota" per quanto riguarda il codice client; non offre un'API utilizzabile eccetto cose, che lo Object
offre già. Il vantaggio principale di averlo: il client può dichiarare variabili di questo tipo e il compilatore è in grado di digitare check. Il tuo framework, tuttavia, rimane l'unico posto dove possono essere create istanze concrete di questo tipo e, quindi, il tuo framework ha il controllo totale su tutti i valori.
Perché non funziona, se rendiamo il tipo root pacchetto-privato? –
Sì, ma è il client indesiderato a vedere questo tipo. Abbiamo solo bisogno di specificare attraverso metodi di fabbrica e di passarlo attraverso i metodi di fabbrica per gli oggetti di pianificazione. –