2016-07-13 3 views
0

Полезно ли определить интерфейс, реализовать интерфейс в базовом абстрактном классе, дать ему поведение по умолчанию, а затем наследовать от базового класса?Интерфейс и базовый Аннотация Класс C#

Или это, что излишнее?

+0

В зависимости от того, чего вы пытаетесь достичь ... Интерфейсы дают вам возможность ретранслировать по контрактам, чтобы вы могли изменить реализацию, не изменяя весь ваш код. Базовые классы полезны для описания поведения по умолчанию. – Thomas

ответ

4

Следует ли использовать интерфейс или абстрактный класс, это два совершенно разных вопроса. Может случиться так, что ответ на вопрос: да, но не имеет ничего общего с другим.

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

Написание интерфейса, а затем его реализация - хорошая практика, когда вы создаете что-то, от чего зависит другой класс (что очень часто бывает.) Например, если вы знаете, что ваш класс будет зависеть от другой класс, который «делает что-то», то вы можете временно приостановить работу над первым классом, чтобы написать интерфейс IDoesSomething, и завершить первый класс, который зависит от IDoesSomething. Вы еще не поняли, что такое реализация, но это не имеет значения, потому что класс, который вы уже пишете, зависит от интерфейса. (Inversion of Control - хорошая практика.) Затем вы можете написать класс, который реализует IDoesSomething.

Просто изложите это на примере. Предположим, что я пишу класс, который обеспечивает Menu объекта, который содержит вложенный список объектов MenuItem:

public class MenuProvider 
{ 
    public Menu GetMenu(string menuId) 
    { 
     //code that gets the menu 
     return menu; 
    } 
} 

Тогда я понимаю, что я собираюсь нужно отфильтровать определенные пункты меню перед его возвращением. Это может быть основано на настройках конфигурации, конкретном пользователе или что-то еще.

Я мог бы написать этот интерфейс:

public interface IMenuFilter 
{ 
    void FilterMenu(Menu menu); 
} 

, а затем изменить мой исходный класс, как это:

public class MenuProvider 
{ 
    private readonly IMenuFilter _menuFilter; 

    public MenuProvider(IMenuFilter menuFilter) 
    { 
     _menuFilter = menuFilter; 
    } 

    public Menu GetMenu(string menuId) 
    { 
     //code that gets the menu 

     //filter the menu 
     _menuFilter.FilterMenu(menu); 
     return menu; 
    } 
} 

Я не знаю, что реализация IMenuFilter будет. На практике это может быть составной состав группы отдельных классов, каждая из которых выполняет один тип фильтрации.Но дело в том, что мне не нужно останавливать то, что я делаю на MenuProvider, чтобы понять это. Я могу написать этот класс и даже проверить его с издевательством IMenuFilter, а затем перейти к написанию специфики этого фильтра.

+0

Спасибо за ответ Скотт! – MaitlandMarshall

2

Есть ли у вас общая функциональность, которую вы хотите разделить между реализациями этого интерфейса? Если это так, создайте абстрактный базовый класс. В противном случае, не беспокойтесь об этом сейчас. Вы всегда можете добавить его позже. Но программирование на интерфейсы - это почти всегда хорошая идея.

1

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

Используйте наследование, если вы хотите наследовать функциональность из базового класса.

Используйте интерфейс, если вы хотите, чтобы разрозненные классы реализовали одни и те же основные функциональные возможности, но не обязательно использовали общий код.

+2

Я лично не согласен с этим. Я думаю, что в достаточно сложных сценариях вполне разумно писать код потребителя по интерфейсу, сохраняя при этом иерархию абстрактных базовых классов, чтобы сохранить ваши конкретные реализации DRY. –

+0

Настоящий пример: программные запросы модулей плагинов (с использованием отражения) для не абстрактных реализаций 'IOutputController'. Плагины (написанные кем-то, кроме основного приложения) реализуют этот интерфейс. Они могут наследоваться от различных ABC, таких как 'OutputControllerBase',' SerialOutputControllerBase' или 'ParallelOutputControllerBase', которые предоставляются основным приложением. Однако, поскольку им нужно только реализовать «IOutputController», они не могут наследовать ни один из них. –

+1

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

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