Üyeleri gizlemek için açık arabirim uygulamasını kullanmak için iyi nedenler nelerdir?


11

C #'ın inceliklerine ilişkin çalışmalarımdan biri sırasında, açık arayüz uygulamasıyla ilgili ilginç bir pasajla karşılaştım.

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.

Kullanımına izin verilmesi object.method()veya yayınlanmasını gerektirme arasındaki fark, ((Interface)object).method()deneyimsiz gözlerime kötü ruhlu bir şaşkınlık gibi görünüyor. Metin bu nesne düzeyinde IntelliSense gelen yöntemini gizler kaydetti, ancak neden istiyor bunu o isim çatışmaları önlemek için gerekli değilse?


Yanıtlar:


12

Arayüzün bir sınıfı, sınıfın bir parçası olarak gerçekten mantıklı olmayan yöntemler uygulamaya zorladığı bir durum düşünün. Bu genellikle arayüzler özellikle büyük olduğunda ve Arayüz Ayrışma İlkesini ihlal ettiğinde ortaya çıkabilir.

Bu sınıfın arabirimi uygulaması gerekir, ancak son derece görünür genel arabirimini anlamlı olmayan yöntemlerle kirletmek yerine, açıkça bulunmasını istemediğiniz yöntemleri açıkça uygulayabilirsiniz. Sınıfın oldukça görünür genel arabirimi, sınıfın nasıl kullanılmasını istediğinizdir ve sınıfa arabirimden erişildiğinde açık uygulama oradadır.


6
Sadece ben miyim yoksa bu kulağa korkunç bir fikir gibi mi geliyor?
Kevin Peno

5
@Kevin, nasıl yani? Bazen arayüz kontrolünüz dışındadır ve onu kullanmak zorundasınız. Zorlayıcı bir arayüzün hasarını azaltmak makul görünmektedir.
Chris Pitman

1
+1, gerçek dünyanın birçok şeyi doğru şekilde yapma yoluna girdiğine işaret etti. @Kevin evet bu korkunç bir fikir ama bazen bir seçiminiz yok ve eğimle çalışmak zorundasınız - onu gizlemek ve gerçekten düzgün bir şekilde yapamadığınızda bir şeyleri düzgün bir şekilde yapmak için bir cephe yapmak daha iyi.
Wayne Molina

@Wayne, böyle bir sistemi isteme / kullanma nedeninizi anlıyorum. Cehennem, muhtemelen bunu tam olarak belirttiğiniz durumda kullanırım. Kısa yorumumun bunun sadece yanlış olduğuna işaret ettiğini düşünüyorum, neden dilde izin verdiniz.
Kevin Peno

1
Aşırı arayüz ayrımı, kompozisyon ve kümelenmenin önünde büyük bir engel olabilir. Örneğin, bir uygulamanın IEnumerable<T>diğer iki kişinin birleşimi gibi davranmasını istediğini düşünün . Eğer IEnumerable<T>onun sayımı biliniyordu olmadığını söylemek bir özellik dahil, potansiyel olarak sonsuz veya bunların ikisinin de bir yöntem ile birlikte kendi sayımı, çoklu toplayan bir sınıf ne olduğunu sormak için IEnumerable<T>verimli bir kısmını bu arada kendine sayısını rapor verebilecek bir birleştirme gibi ve davranır kapsüllenmiş koleksiyonlar sayılarını biliyordu.
supercat

4

Bulduğum en kullanışlı uygulama fabrikaları uygulamak. Birçok durumda, fabrika içinde değiştirilebilen ancak harici sınıflarla değiştirilemeyen sınıflar oluşturmak yararlıdır. Bu, Java'yı iç sınıfları kullanarak, alanları ve ayarlayıcılarını özel yaparak ve yalnızca alıcıları herkese açık üye olarak göstererek kolayca uygulanabilir. Ancak C #, aynı şeyi elde etmek için açık arabirimler kullanmak zorunda kaldı. Daha fazla açıklayacağım:

Java'da, iç sınıf VE dış sınıf, birbirlerinin özel üyelerine erişebilir, bu da sınıflar çok yakından ilişkili olduğu için tam mantıklıdır. Aynı kod dosyasındadır ve muhtemelen aynı geliştirici tarafından geliştirilmiştir. Bu, iç sınıftaki özel alanlara ve yöntemlere fabrika tarafından değerlerini değiştirmek için erişilebileceği anlamına gelir. Ancak harici sınıflar, kamu alanlarından gelenler dışında bu alanlara erişemeyecektir.

Ancak, C # 'da, dış sınıflar iç sınıfların özel üyelerine erişemez, böylece kavram doğrudan uygulanabilir değildir. Dış sınıfta özel bir arabirim tanımlayıp iç sınıfta açıkça uygulayarak açık bir arabirimi geçici çözüm olarak kullandım. Bu şekilde, yalnızca dış sınıf bu arabirimdeki yöntemlere Java'da olduğu gibi erişebilir (ancak alanlar değil, yöntemler olmalıdır).

Misal:

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

Bunun için açık arayüzler kullanırdım.


3

Bir sınıf, aynı imzalı bir üye içeren iki arabirim uygularsa, o üyeyi sınıfta uygulamak her iki arabirimin de o üyeyi uygulama olarak kullanmasına neden olur. Aşağıdaki örnekte, tüm çağrılar Paintaynı yöntemi çağırır. 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");
    }
}

Buna karşılık, bunlardan birinin (veya her ikisinin) açıkça uygulanması, her biri için farklı davranışlar belirlemenize olanak tanır.


1

Açık arabirimler, bir nesnenin iki veya daha fazla farklı iletişim formuna sahip olması durumunda kullanışlıdır.

Örneğin, üst öğeyle iletişim kurması gereken alt nesne koleksiyonunu tutan bir nesne.

Yalnızca harici arayanlar tarafından erişilebilir olmasını istediğimiz bazı işlemler ve yalnızca alt nesneler tarafından erişilebilir olmasını istediğimiz bazı işlemler vardır.

Açık arayüzler bu bölünmenin sağlanmasına yardımcı olur.

    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

Belki de kullanıcılar için yararlı bir işlevsellik varsa, ancak yalnızca ne yaptığınızı gerçekten biliyorsanız (işlev hakkında bilgi edinmek için belgeleri okumuş olmanız yeterli), ancak bu muhtemelen bir şeyleri kırmazsa.

Bunu neden sağlamak yerine yapmak istiyorsunuz, bilmiyorum ikinci bir "gelişmiş özellikler arayüzü" deyin.


0

Kod genellikle yazıldığından daha fazla okunur ve Intellisense'i yalnızca kod yazmak için kullanırım. Ben sadece Intellisense güzel yapmak için özel bir yol kodu yazmak olmaz.

Özellikle nasıl olduğunu görmüyorum

((Interface) object) .method (), object.method () öğesinden daha fazla okunabilir.

Belirli bir nesne üzerinde çok fazla yöntemim varsa, onun bir tanrı nesnesi olup olmadığını sorgulayabilirim ve aslında birden çok daha basit nesneye bölünmesi gerekir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.