Apa alasan bagus untuk menggunakan implementasi antarmuka eksplisit untuk tujuan menyembunyikan anggota?


11

Dalam salah satu studi saya tentang seluk-beluk C #, saya menemukan sebuah bagian yang menarik mengenai implementasi antarmuka eksplisit.

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.

Perbedaan antara membiarkan penggunaan object.method()atau membutuhkan pengecoran ((Interface)object).method()tampak seperti kebingungan yang kejam bagi mata saya yang tidak berpengalaman. Teks mencatat bahwa ini akan menyembunyikan metode dari Intellisense di tingkat objek, tetapi mengapa Anda ingin melakukan itu jika tidak perlu untuk menghindari konflik nama?


Jawaban:


12

Bayangkan sebuah situasi di mana antarmuka memaksa kelas untuk mengimplementasikan metode yang sebenarnya tidak masuk akal sebagai bagian dari kelas. Ini sering dapat terjadi ketika antarmuka sangat besar dan melanggar Prinsip Segregasi Antarmuka.

Kelas ini perlu mengimplementasikan antarmuka, tetapi alih-alih mencemari antarmuka publiknya yang sangat kasat mata dengan metode yang tidak masuk akal, Anda dapat secara eksplisit menerapkan metode yang tidak ingin tersedia secara jelas. Antarmuka publik yang sangat terlihat dari kelas adalah bagaimana Anda ingin kelas digunakan, dan implementasi eksplisit ada ketika kelas diakses melalui antarmuka.


6
Apakah hanya saya, atau apakah ini terdengar seperti ide yang buruk?
Kevin Peno

5
@ Kevin, bagaimana bisa begitu? Terkadang antarmuka di luar kendali Anda, dan Anda harus menggunakannya. Mengurangi kerusakan antarmuka sombong tampaknya masuk akal.
Chris Pitman

1
+1 untuk menunjukkan bahwa berkali-kali dunia nyata menghalangi cara yang benar dalam melakukan sesuatu. @ Kevin ya itu ide yang buruk tapi kadang-kadang Anda tidak punya pilihan dan harus bekerja dengan slop - lebih baik untuk menyembunyikan itu pergi dan membuat fasad melakukan hal-hal dengan benar ketika Anda tidak bisa benar-benar melakukannya dengan benar.
Wayne Molina

@Wayne, saya mengerti alasan Anda ingin / menggunakan sistem seperti itu. Sial, saya mungkin akan menggunakannya persis seperti yang Anda sebutkan. Saya kira komentar singkat saya benar-benar hanya menunjukkan bahwa ini tidak pantas, jadi mengapa mengizinkannya dalam bahasa.
Kevin Peno

1
Pemisahan antarmuka yang berlebihan dapat menjadi hambatan utama untuk komposisi dan agregasi. Pertimbangkan, misalnya, bahwa seseorang ingin memiliki implementasi IEnumerable<T>yang berperilaku sebagai gabungan dari dua lainnya. Jika IEnumerable<T>menyertakan properti untuk mengatakan apakah penghitungannya diketahui, berpotensi tak terbatas, atau tidak, bersama dengan metode untuk bertanya apa penghitungannya, kelas yang menggabungkan banyak IEnumerable<T>dan bertingkah laku sebagai gabungan dapat secara efisien melaporkan penghitungannya dalam kasus bahwa beberapa koleksi yang dienkapsulasi tahu jumlah mereka.
supercat

4

Aplikasi paling berguna yang saya temukan adalah dengan menerapkan pabrik. Dalam banyak kasus, berguna untuk membuat kelas yang bisa berubah di dalam pabrik tetapi tidak dapat diubah ke kelas eksternal. Ini dapat dengan mudah diimplementasikan di Jawa menggunakan kelas dalam, dengan membuat bidang dan setternya pribadi dan hanya mengekspos getter sebagai anggota publik. Namun dalam C #, saya harus menggunakan antarmuka eksplisit untuk mencapai hal yang sama. Saya akan jelaskan lebih lanjut:

Di Jawa, kelas dalam DAN kelas luar dapat mengakses anggota pribadi satu sama lain, yang masuk akal karena kelas-kelas tersebut sangat terkait erat. Mereka berada dalam file kode yang sama dan mungkin dikembangkan oleh pengembang yang sama. Ini berarti bahwa bidang dan metode pribadi di kelas dalam masih dapat diakses oleh pabrik untuk mengubah nilai-nilai mereka. Tetapi kelas eksternal tidak akan dapat mengakses bidang ini kecuali melalui pengambil publik mereka.

Namun, dalam C #, kelas luar tidak dapat mengakses anggota pribadi kelas dalam sehingga konsep itu tidak langsung berlaku. Saya menggunakan antarmuka eksplisit sebagai solusi dengan mendefinisikan antarmuka pribadi di kelas luar dan secara eksplisit mengimplementasikannya di kelas dalam. Dengan cara ini, hanya kelas luar yang dapat mengakses metode di antarmuka ini dengan cara yang sama dilakukan di Jawa (tetapi mereka harus metode, bukan bidang).

Contoh:

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;
    }
}

Itulah yang akan saya gunakan untuk antarmuka eksplisit.


3

Jika suatu kelas mengimplementasikan dua antarmuka yang berisi anggota dengan tanda tangan yang sama, maka mengimplementasikan anggota tersebut di kelas akan menyebabkan kedua antarmuka menggunakan anggota tersebut sebagai implementasinya. Dalam contoh berikut, semua panggilan untuk Paintmemanggil metode yang sama. 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");
    }
}

Sebaliknya, penerapan eksplisit satu (atau keduanya) memungkinkan Anda menentukan perilaku yang berbeda untuk masing-masing.


1

Antarmuka eksplisit berguna ketika salah satu objek memiliki dua atau lebih bentuk komunikasi yang sangat berbeda.

Misalnya, objek yang menyimpan koleksi objek anak yang perlu berkomunikasi dengan orang tua.

Ada beberapa tindakan yang kami hanya ingin dapat diakses oleh penelepon eksternal dan beberapa tindakan kami hanya ingin dapat diakses oleh objek anak.

Antarmuka eksplisit membantu memastikan kesenjangan ini.

    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();
        }
    }

0

Mungkin jika Anda memiliki fungsionalitas yang bermanfaat bagi pengguna, tetapi hanya jika Anda benar-benar tahu apa yang Anda lakukan (cukup untuk membaca dokumentasi untuk mempelajari tentang fungsi tersebut) tetapi itu kemungkinan akan merusak banyak hal jika Anda tidak.

Mengapa Anda melakukan itu daripada memberikan, katakanlah "antarmuka fitur lanjutan" kedua yang saya tidak tahu.


0

Kode umumnya dibaca lebih dari yang tertulis dan saya hanya menggunakan Intellisense untuk menulis kode dengan cepat. Saya tidak akan menulis kode dengan cara tertentu hanya untuk membuat Intellisense lebih bagus.

Saya tidak begitu mengerti caranya

((Antarmuka) objek) .method () lebih mudah dibaca daripada object.method ().

Jika saya memiliki banyak metode pada objek tertentu, saya mungkin mempertanyakan apakah ini objek dewa atau tidak dan sebenarnya harus dipecah menjadi beberapa objek yang lebih sederhana.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.