Наследование от общего предка
Проблема наследования от общего предка характерна, в первую очередь, для множественного наследования классов. Если класс C является наследником классов A и B, а те, в свой черед, являются наследниками класса Parent, то класс наследует свойства и методы своего предка Parent дважды, один раз получая их от класса A, другой от - B. Это явление называется еще дублирующим наследованием. Для классов ситуация осложняется тем, что классы A и B могли по-разному переопределить методы родителя и для потомков предстоит сложный выбор реализации.
Для интерфейсов сама ситуация дублирующего наследования маловероятна, но возможна, поскольку интерфейс, как и любой класс, может быть наследником другого интерфейса. Поскольку у интерфейсов наследуются только сигнатуры, а не реализации, как в случае классов, то проблема дублирующего наследования сводится к проблеме коллизии имен. По-видимому, естественным решением этой проблемы в данной ситуации является склеивание, когда методам, пришедшим разными путями от одного родителя, будет соответствовать единая реализация.
Начнем наш пример с наследования интерфейсов:
public interface IParent { void ParentMethod(); } public interface ISon1:IParent { void Son1Method(); } public interface ISon2:IParent { void Son2Method(); }
Два сыновних интерфейса наследуют метод своего родителя. А теперь рассмотрим класс, наследующий оба интерфейса:
public class Pars:ISon1, ISon2 { public void ParentMethod() { Console.WriteLine("Это метод родителя!"); } public void Son1Method() { Console.WriteLine("Это метод старшего сына!"); } public void Son2Method() { Console.WriteLine("Это метод младшего сына!"); } }//class Pars
Класс обязан реализовать метод ParentMethod, приходящий от обоих интерфейсов. Понимая, что речь идет о дублировании метода общего родителя - интерфейса IParent, лучшей стратегией реализации является склеивание методов в одной реализации, что и было сделано. Приведу тестирующую процедуру, где создается объект класса и три объекта интерфейсных классов, каждый из которых может вызывать только методы своего интерфейса:
public void TestIParsons() { Console.WriteLine("Объект класса вызывает методы трех интерфейсов!"); Cli.Pars ct = new Cli.Pars(); ct.ParentMethod(); ct.Son1Method(); ct.Son2Method(); Console.WriteLine("Интерфейсный объект 1 вызывает свои методы!"); Cli.IParent ip = (IParent)ct; ip.ParentMethod(); Console.WriteLine("Интерфейсный объект 2 вызывает свои методы!"); Cli.ISon1 ip1 = (ISon1)ct; ip1.ParentMethod(); ip1.Son1Method(); Console.WriteLine("Интерфейсный объект 3 вызывает свои методы!"); Cli.ISon2 ip2 = (ISon2)ct; ip2.ParentMethod(); ip2.Son2Method(); }
Результаты работы тестирующей процедуры показаны на рис. 19.3.
Рис. 19.3. Дублирующее наследование интерфейсов