Casi d'uso per le interfacce "private"?

8

Mi chiedevo se esistesse un caso d'uso valido per essere in grado di definire correttamente le proprietà e le funzioni interne specifiche di una classe in modo simile a come un'interfaccia definisce le proprietà e le funzioni pubbliche di una classe.

Immagina l'attività che devi costruire per una classe che descrive un essere umano.

Ovviamente, ogni umano è una creatura umanoide, ma non tutte le creature umanoidi sono umane quindi probabilmente avresti un'interfaccia IHumanoide con funzioni come queste (dato che non è utile inserire il codice del corpo nella classe):

public interface IHumanoid {
    function get head():IHead;
    function get torso():ITorso;
    function get leftArm():IArm;
    function get rightArm():IArm;
    function get leftLeg():ILeg;
    function get rightLeg():ILeg;
}

Inoltre, e ovviamente, ogni essere umano è un mammifero ma non tutti i mammiferi sono umani, quindi probabilmente c'è un'altra interfaccia IMammal con due definizioni per maschi e femmine che fluttuano da qualche parte:

public interface IMammal {
    function procreate(partner:IMammal):void;
}

public interface IMaleMammal extends IMammal {
    function inseminate(female:IFemaleMammal):void;
}

public interface IFemaleMammal extends IMammal {
    function conceive(partner:IMaleMammal):Boolean;
    function giveBirth():IMammal;
    function nurse(offspring:IMammal):void;
}

Quindi la nostra classe probabilmente assomiglia a qualcosa del genere ora:

public class Human implements IHumanoid, IMammal {
    private var _head:IHead;
    private var _torso:ITorso;
    private var _leftArm:IArm;
    private var _rightArm:IArm;
    private var _leftLeg:ILeg;
    private var _rightLeg:ILeg;

    public function Human() {
        // ctor...
    }

    public function get head():IHead {
        return _head;
    }

    public function get torso():ITorso {
        return _torso;
    }

    public function get leftArm():IArm {
        return _leftArm;
    }

    public function get rightArm():IArm {
        return _rightArm;
    }

    public function get leftLeg():ILeg {
        return _leftLeg;
    }

    public function get rightLeg():ILeg {
        return _rightLeg;
    }

    public function procreate(partner:IMammal):void {
        // "abstract" function
    }
}

public class MaleHuman extends Human implements IMaleMammal {
    override public function procreate(partner:IMammal):void {
        if (partner is IFemaleMammal) {
            inseminate(partner);
        }
    }

    public function inseminate(female:IFemaleMammal):void {
        female.conceive(this);
    }
}

public class FemaleHuman extends Human implements IFemaleMammal {
    override public function procreate(partner:IMammal):void {
        if (partner is IMaleMammal) {
            conceive(partner);
        }
    }

    public function conceive(partner:IMaleMammal):Boolean {
        // ...
    }

    public function giveBirth():IMammal {
        // ...
    }

    public function nurse(offspring:IMammal):void {
        // ...
    }
}

Da questo possiamo implementare ulteriormente le nostre classi e tutto funziona bene fino a quando non avremo il compito di utilizzare le interfacce esistenti per implementare altre classi. Forse un gorilla, un'orca e un ornitorinco.

Ignorando l'enorme problema che l'ornitorinco porrà alla nostra attuale struttura dell'interfaccia (* cough * uovo che posa mammifero * tosse *), abbiamo il "problema" che nulla ci impedisce di dare il cervello del gorilla 2, l'orca 8 polmoni e il platypus mezza dozzina di fegati. E mentre noi potremmo essere abbastanza disciplinati da seguire la struttura, i mammiferi in genere non possono garantire lo stesso se apriamo l'API per altri sviluppatori che potrebbero codificare alcune cose seriamente incasinate che sembrano ancora valide per il mondo esterno.

Quindi mi chiedevo se esistesse un caso d'uso valido per creare qualcosa come una "interfaccia privata" che definisce funzioni e proprietà non pubbliche. Forse qualcosa in questo senso:

public structure SMammal {
    function get brain():IBrain;
    function get liver():ILiver;
    function get leftLung():ILung;
    function get rightLung():ILung;
    function get leftKidney():IKidney;
    function get rightKidney():IKidney;
}

public class Human implements IHumanoid, IMammal follows SMammal {
    private function get brain():IBrain {
        // ...
    }

    private function get liver():ILiver {
        // ...
    }

    // etc. etc.
}

Questa caratteristica esiste in qualsiasi linguaggio di programmazione? Le classi astratte possono essere utilizzate per risolvere questo? O non dovremmo preoccuparci di questo a patto che l'interfaccia pubblica funzioni in qualche modo come previsto?

    
posta arotter 19.08.2012 - 00:06
fonte

4 risposte

3

And while we might be disciplined enough to follow the structure mammals typically have we cannot guarantee the same if we open the API for other developers who might code some seriously screwed up things which still look okay to the outside world.

Che cosa guadagni esattamente costringendoli a seguire la tua struttura? Puoi rompere alcuni usi avanzati, forse c'è un caso per un animale con più cervelli. E il programmatore client può rovinare l'implementazione di una classe in così tanti modi pazzi che tentare di impedire che ciò accada è come provare a chiudere una finestra nel tentativo di tenere un cavallo in un granaio.

Non trattare i tuoi programmatori come i prigionieri. Se seguono l'interfaccia pubblica, esegui il codice.

    
risposta data 19.08.2012 - 16:25
fonte
1

Poiché un tipo di interfaccia è un membro pubblico, per impostazione predefinita tutto ciò che è al suo interno dovrebbe essere pubblico ma ho visto questo:

link

da msdn:

Interfaces consist of methods, properties, events, indexers, or any combination of those four member types. An interface cannot contain constants, fields, operators, instance constructors, destructors, or types. It cannot contain static members. Interfaces members are automatically public, and they cannot include any access modifiers.

link

    
risposta data 19.08.2012 - 01:15
fonte
0

Does such a feature exist in any programming language? Can abstract classes be used to solve this? Or shouldn't we care about this at all as long as the public interface somehow works as expected?

Di sicuro sì. Quasi tutte le funzioni esistono in alcune lingue.

Ad esempio, in Objective-C ++ (programmazione iOS / Mac) è una procedura standard per una classe avere almeno due interfacce. Su questo è pubblico, e uno che è privato. A volte hanno anche interfacce aggiuntive definite altrove (ad esempio, la classe string di livello basso ha un'interfaccia per eseguire operazioni di disegno della schermata della GUI sulla stringa, che è definita in una struttura / libreria completamente separata da quella che definisce la stringa classe).

Fondamentalmente il modo in cui tratto pubblico / privato è semplice:

Gli elementi dell'interfaccia pubblica non possono mai essere modificati. Ogni volta che rifattori o migliora il tuo codice, l'interfaccia pubblica deve ancora comportarsi esattamente allo stesso modo di prima.

Le interfacce private, d'altra parte, possono essere modificate o completamente rimosse quando vuoi. Finché si aggiorna tutto il codice della classe per capire il nuovo comportamento, stai bene. Spesso l'interfaccia pubblica sarà piena di uno o due metodi di linea che passano il lavoro reale all'interfaccia privata.

Objective-C ++ ha anche il concetto di "protetto" nell'interfaccia, dove qualcosa è disponibile per sottoclassi ma non per le classi esterne.

Di solito il mio codice è diviso a metà e metà tra pubblico e privato. Non uso molto la protezione, anche se è utile una volta ogni tanto.

    
risposta data 19.08.2012 - 04:30
fonte
0

Almeno nei linguaggi .NET, è possibile applicare uno specificatore di accesso a un'interfaccia. Ciò può essere utile quando alcune combinazioni delle classi interne di un assembly condividono le abilità comuni, ma tali combinazioni e abilità non si adattano a una relazione gerarchica. Il fatto che le abilità non si adattino a una relazione gerarchica rende necessario l'uso di interfacce per rappresentarle, ma non implica in alcun modo che il codice esterno debba essere autorizzato a definire i tipi che pretendono di implementare le interfacce. Inoltre, le interfacce non possono contenere alcun metodo i cui tipi di parametri o tipi di ritorno abbiano un accesso più ristretto rispetto alle interfacce stesse. Se la classe Fred è dichiarata internal , e un'interfaccia IFred ha un metodo che restituisce un Fred , quindi l'interfaccia deve essere dichiarata internal . Se la classe nidificata Fred.Joe è private e l'interfaccia nidificata Fred.IJoe ha un metodo che restituisce un Fred.Joe , quindi Fred.IJoe deve essere ugualmente dichiarato private .

    
risposta data 17.11.2014 - 21:11
fonte

Leggi altre domande sui tag