2013-03-11 3 views
1

Я натолкнулся на немного кода и не совсем уверен, почему он работает или почему вы хотите сделать это таким образом. Мне бы это понравилось, если бы кто-то мог оторвать его. Я хорошо понимаю концепции ООП, я просто не видел эту технику раньше. БлагодаряМетоды уровня интерфейса и абстрактного класса защиты

Вот пример:

public interface IInterface 
{ 
    IEnumerable<object> DoSomething(); 
} 

public abstract class MyBase : IInterface 
{ 
    protected MyBase() 
    { 
    } 

    IEnumerable<object> IInterface.DoSomething() 
    { 
     return DoSomething(); 
    } 

    protected virtual IEnumerable<object> DoSomething() 
    { 
     return new List<object>(); 
    } 
} 

public class MyClass : MyBase 
{ 
    internal MyClass() : base() {} 

    protected override IEnumerable<object> DoSomething() 
    { 
      return new List<object>(); 
    } 
} 
+1

Непонятно, какой аспект примера вы путаете. –

+0

Я предполагаю, что это явная реализация интерфейса с защищенной неявной реализацией (если это так, я бы сказал, что реализации неявного интерфейса являются общедоступными). –

+0

Приношу свои извинения. Часть, которая меня смущает, - это то, что смотрит на меня как на частную реализацию IInterface.DoSomething, возвращающей виртуальную DoSomething. Я также обратил внимание на IInterface. требуется для его компиляции. – Kirby

ответ

1

Если вы говорите об этой строке кода:

IEnumerable<object> IInterface.DoSomething() 

Это называется explicit interface implementation.

Это заставляет потребителей получать доступ к этому методу только через интерфейс, , а не непосредственно к вашему классу.

Вышеупомянутый метод не является частным, он явно не установлен как открытый в коде. Фактически, при явной реализации интерфейса вы даже не можете использовать модификаторы доступа.

Одна из причин такого подхода заключается в усилении практики кодирования. Если вы являетесь разработчиком этого класса, и вы знаете, что его следует использовать только через интерфейс, это способ заставить это произойти.

+0

Я знаю об явном интерфейсе imp, и я знаю, что это пригодится, когда вы используете несколько интерфейсов, которые имеют одинаковые именованные методы. Я все еще не уверен, почему программист сделал это и какую пользу он приносит. – Kirby

+1

Речь идет не только об использовании одного интерфейса при наличии двух определенных; речь идет о принуждении класса к потреблению через интерфейс вместо прямого использования самого класса (даже если задействован только один интерфейс). Мой ответ показывает причину этого. –

+0

В C# вы не можете изменять явную реализацию интерфейса - она ​​всегда закрыта. В VB.NET я считаю, что вы можете сделать явную реализацию независимо от того, какой доступ вы хотите. Лично мне лучше нравится C#. –

0

Off верхней части моей головы, у меня возникают проблемы мышления практического использования для этого, но одна вещи, что это решает, что объекты типа MyBase или его подклассы не имеют видимый LY DoSomething() метода public или internal :

MyClass a = new MyClass(); 
a.DoSomething(); // Compile error 

но метод DoSomething() видна, когда объект используется в качестве IInterface:

void AMethod(IInterface i) 
{ 
    i.DoSomething(); // compiles just fine 
} 

void AnotherMethod(MyBase a) 
{ 
    AMethod(a); // as does this 
} 

Создание без явной версии protected virtual позволяет подклассам переопределять поведение метода DoSomething().

Это способ реализации метода, который не может быть вызван непосредственно при работе с MyBase с, как MyBase s, но может использоваться, когда они обрабатываются как IInterfaces. Нет ничего, что помешало бы кому-то сделать это: ((IInterface)a).DoSomething();, но похоже, что сокрытие сделано по смысловым соображениям.

+0

Для получения дополнительной информации об использовании в той же сборке есть фабричный класс, который создает и возвращает MyClass. Класс, который использует этот MyClass, также находится в одной и той же сборке и вызывает метод без проблемы. Пример var myClass = SomeFactory.GetMyClass(); myClass.DoSomething() – Kirby

+0

Является ли класс с этим кодом в нем наследованием от 'MyBase'? – JLRishe

+0

Это, вероятно, потому, что 'GetMyClass()' возвращает интерфейс, а не конкретный myBase или myClass. –

0

Я считаю, что это реализация шаблона шаблона, как описано here. Обычно вы видите шаблон, используемый вместе с шаблоном strategy. В вашем конкретном примере пользователи IInterface могут вызвать метод DoSomething без учета того, как конкретный подкласс реализовал этот метод.

Этот вид программирования OO позволяет вам воспользоваться множеством других шаблонов, таких как AbstractFactory, для создания ваших конкретных подклассов MyBase, которые реализуют IInterface.

0

Важно отметить, что два метода DoSomething не имеют никакого отношения друг к другу - у них просто одноименное имя.

В принципе, у вас есть обычный интерфейс, который предоставляет метод DoSomething, поэтому вызывающий, который имеет объект IInterface, может его вызвать. Затем он, в свою очередь, передаст вызов соответствующей реализации защищенного метода DoSomething, который может быть либо из базового класса, либо из производного.

Явная реализация, как это заставляет вас кодировать по контракту вместо реализации - на самом деле не обеспечивает никакой реальной защиты, просто затрудняет случайное использование неправильного типа при объявлении переменной. Они так же, как легко могли бы сделать:

public abstract class MyBase : IInterface { 
    public virtual IEnumerable<object> DoSomething() { 
     // blah 
    } 
} 

public class MyClass : MyBase { 
    public override IEnumerable<object> DoSomething() { 
     // blah 
    } 
} 

но пусть бы вы назвали DoSomething на переменной, объявленной в MyClass или MyBase, которые вы не можете их сделать.

+0

Это объяснение делает меня намного понятнее. Согласитесь ли вы с nattyddubbs, что это выглядит как шаблон шаблонов? Мне нужно будет кое-что прочитать по этой схеме. – Kirby

+0

Это похоже на право - никогда раньше не называлось шаблоном шаблона, но это довольно простой основанный на наследовании ООП-базовый класс и переопределенные методы в ваших дочерних классах, чтобы заставить их вести себя так, как вы этого хотите. –

+0

хотел дать вам реквизит, проголосовав за вас, но мой представитель еще недостаточно высок. Еще раз спасибо за указание именования самородок! – Kirby

0

В C#, явно реализующем интерфейс с использованием закрытого метода, который ничего не делает, кроме вызова защищенного виртуального метода, позволяет производным классам большую гибкость в отношении того, что они хотят делать с интерфейсом; методу должно быть присвоено имя другое, чем имя метода интерфейса (в приведенном выше примере это может быть DoSomething_Prot). Явная реализация интерфейса делает невозможным повторную реализацию производного класса для реализации базового класса, но если единственное, что делает реализация базового класса, - это привязка к защищенному виртуальному или абстрактному методу, нет необходимости в производном класса для повторной реализации интерфейса. Кроме того, даже если производный класс должен был повторно реализовать интерфейс либо намеренно, либо в результате ковариации, он все равно мог бы вызывать «кишки» реализации базового класса с использованием защищенного метода из базового класса.

Ввод всего кода для реализации интерфейса в виртуальном виртуальном методе, который неявно реализует интерфейс, лучше, чем перенос кода в явную реализацию, поскольку код производного класса может обычно связываться с частным членом. Однако такой подход требует, чтобы все производные классы публично реализовывали метод с одной и той же сигнатурой. Хотя это может показаться тем, чего, естественно, ожидать в любом случае, это не всегда. Например, в приведенном выше примере производный класс может пожелать, чтобы его метод DoSomething возвращал тип, отличный от IEnumerable<object> (например, он мог бы вернуть IList<Kangaroo>). Метод, который реализует interfae, все равно должен будет возвращать точный тип IList<Kangaroo>, но код, который знал, что он имеет дело с производным типом, может использовать возвращаемый тип как IList<Kangaroo> без типизации. Если фактический код метода был в методе DoSomething_Prot(), производный класс мог бы переопределить DoSomething_Prot и объявить new public IList<Kangaroo> DoSomething(). Если метод базового класса был вызван DoSomething(), для производного класса не было бы способа переопределить его и определить новый метод с другим типом возвращаемого значения.

Смежные вопросы