Quali sono i buoni motivi per usare l'implementazione esplicita dell'interfaccia al solo scopo di nascondere i membri?

8

Durante uno dei miei studi sulla complessità di C #, mi sono imbattuto in un passaggio interessante riguardante l'implementazione esplicita dell'interfaccia.

While this syntax is quite helpful when you need to resolve name clashes, you can use explicit interface implementation simply to hide more "advanced" members from the object level.

La differenza tra consentire l'uso di object.method() o richiedere il cast di ((Interface)object).method() sembra un'offuscamento meschino ai miei occhi inesperti. Il testo ha rilevato che questo nasconderà il metodo da Intellisense a livello di oggetto, ma perché dovresti vuoi farlo se non fosse necessario per evitare conflitti di nomi?

    
posta Nathanus 20.04.2011 - 22:50
fonte

6 risposte

10

Immagina una situazione in cui un'interfaccia costringa una classe a implementare metodi che in realtà non hanno senso come parte della classe. Questo può spesso accadere quando le interfacce sono particolarmente grandi e violano il principio di segregazione dell'interfaccia.

Questa classe deve implementare l'interfaccia, ma invece di inquinare la sua interfaccia pubblica altamente visibile con metodi che non hanno senso, puoi implementare esplicitamente quei metodi che non vuoi essere ovviamente disponibili. L'interfaccia pubblica altamente visibile della classe è il modo in cui si desidera utilizzare la classe e l'implementazione esplicita è presente quando si accede alla classe tramite l'interfaccia.

    
risposta data 20.04.2011 - 23:31
fonte
4

L'applicazione più utile che ho trovato è con le fabbriche di implementazione. In molti casi, è utile creare classi mutabili all'interno della fabbrica ma non modificabili per classi esterne. Questo può essere facilmente implementato in Java usando classi interne, rendendo privati i campi e i loro setter e esponendo i getter come membri pubblici. Tuttavia in C #, ho dovuto usare interfacce esplicite per ottenere la stessa cosa. Spiegherò ulteriormente:

In Java, la classe interna AND la classe esterna possono accedere a membri privati l'una dell'altra, il che ha perfettamente senso poiché le classi sono strettamente correlate. Sono nello stesso file di codice e sono probabilmente sviluppati dallo stesso sviluppatore. Ciò significa che i campi e i metodi privati nella classe interna possono ancora essere utilizzati dalla fabbrica per modificare i loro valori. Ma le classi esterne non potranno accedere a questi campi se non attraverso i loro getter pubblici.

Tuttavia, in C #, le classi esterne non possono accedere ai membri privati delle classi interne in modo tale che il concetto non sia direttamente applicabile. Ho usato un'interfaccia esplicita come soluzione alternativa definendo un'interfaccia privata nella classe esterna e implementandola esplicitamente nella classe interna. In questo modo, solo la classe esterna può accedere ai metodi in questa interfaccia nello stesso modo in cui viene eseguita in Java (ma devono essere metodi, non campi).

Esempio:

public class Factory
{
    // factory method to create a hard-coded Mazda Tribute car.
    public static Car CreateCar()
    {
        Car car = new Car();

        // the Factory class can modify the model because it has access to
        // the private ICarSetters interface
        ((ICarSetters)car).model = "Mazda Tribute";

        return car;
    }

    // define a private interface containing the setters.
    private interface ICarSetters
    {
        // define the setter in the private interface
        string model { set; }
    }

    // This is the inner class. It has a member "model" that should not be modified
    // but clients, but should be modified by the factory.
    public class Car: ICarSetters
    {
        // explicitly implement the setter
        string ICarSetters.model { set; }

        // create a public getter
        public string model { get; }
    }
}

class Client
{
    public Client()
    {
        Factory.Car car = Factory.CreateCar();

        // can only read model because only the getter is public
        // and ICarSetters is private to Factory
        string model = car.model;
    }
}

Questo è ciò per cui utilizzerei interfacce esplicite.

    
risposta data 26.02.2012 - 09:41
fonte
3

Se una classe implementa due interfacce che contengono un membro con la stessa firma, implementare quel membro sulla classe farà sì che entrambe le interfacce utilizzino tale membro come implementazione. Nell'esempio seguente, tutte le chiamate a Paint invocano lo stesso metodo. C #

class Test 
{
    static void Main()

    {
        SampleClass sc = new SampleClass();
        IControl ctrl = (IControl)sc;
        ISurface srfc = (ISurface)sc;

        // The following lines all call the same method.
        sc.Paint();
        ctrl.Paint();
        srfc.Paint();
    }
}


interface IControl
{
    void Paint();
}
interface ISurface
{
    void Paint();
}
class SampleClass : IControl, ISurface
{
    // Both ISurface.Paint and IControl.Paint call this method. 
    public void Paint()
    {
        Console.WriteLine("Paint method in SampleClass");
    }
}

Al contrario, l'implementazione esplicita di uno (o entrambi) consente di specificare un comportamento diverso per ciascuno.

    
risposta data 29.09.2015 - 23:18
fonte
1

Le interfacce esplicite sono utili quando un oggetto ha due o più forme di comunicazione molto distinte.

Ad esempio, un oggetto che gestisce una raccolta di oggetti figlio che devono comunicare con il genitore.

Ci sono alcune azioni che vogliamo solo accessibili ai chiamanti esterni e alcune azioni che vogliamo solo accessibili agli oggetti figli.

Le interfacce esplicite aiutano a garantire questa divisione.

    static void Main(string[] args)
    {
        var parent = new Parent();
        parent.DoExternalStuff();
    }

    interface IExternal {
        void DoExternalStuff();
    }

    interface IInternal {
        void DoInternalStuff();
    }

    class Parent : IExternal, IInternal
    {
        public Parent()
        {
            var child = new Child(this);
        }

        public void DoExternalStuff()
        {
           // do something exciting here for external callers
        }

        void IInternal.DoInternalStuff()
        {
            // do something exciting here for internal callers
        }
    }

    class Child
    {
        public Child(IInternal parent)
        {
            parent.DoInternalStuff();
        }
    }
    
risposta data 30.09.2015 - 01:12
fonte
0

Forse se avessi funzionalità che erano utili per gli utenti, ma solo se sapessi veramente cosa stai facendo (basta aver letto la documentazione per conoscere la funzione) ma è probabile che rompa le cose se non lo fai t.

Perché dovresti farlo piuttosto che fornire, ad esempio, una seconda "interfaccia delle funzionalità avanzate" che non conosco.

    
risposta data 20.04.2011 - 23:14
fonte
0

Il codice viene generalmente letto più di quanto non sia scritto e io uso solo Intellisense per scrivere codice velocemente. Non scriverei codice in un modo particolare solo per rendere Intellisense più bello.

Non vedo in particolare come

(oggetto Interface)) .method () è più leggibile di object.method ().

Se avessi molti metodi su un particolare oggetto, potrei chiedermi se sia o meno un oggetto divino e debba essere effettivamente suddiviso in più oggetti più semplici.

    
risposta data 20.04.2011 - 23:17
fonte

Leggi altre domande sui tag