Проект наследования с использованием интерфейса + абстрактный класс. Хорошая практика? - PullRequest
12 голосов
/ 18 декабря 2008

Я не совсем уверен, как озаглавить этот вопрос, но в основном у меня есть такой интерфейс:

public interface IFoo
{
    string ToCMD();
}

пара абстрактных классов, которые реализуют IFoo как:

public abstract class Foo : IFoo
{
   public abstract string ToCMD();
}

public abstract class Bar : IFoo
{
    public abstract string ToCMD();
}

затем классы, которые наследуют Foo и Bar:

public class FooClass1 : Foo
{
    public override string ToCMD()
    {return "Test";}
} ///there are about 10 foo classes.

public class BarClass : Bar
{
    public override string ToCMD()
    {return "BarClass";}
} ///about the same for bar classes.

Я делаю это так, чтобы, когда у меня был свой список, например:

public class Store<T> : List<T>  where T : IFoo {}

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

Что-то вроде:

Store<Foo> store = new Store<Foo>(); //Only Foo types will work.
store.Add(new FooClass1()); //Will compile.

Store<IFoo> store = new Store<IFoo>(); //All IFoo types will work.
store.Add(new FooClass1()); //Will compile.
store.Add(new BarClass()); //Will compile.

Мой вопрос таков: это нормально? или есть лучший способ?

РЕДАКТИРОВАТЬ: Фото-> alt text

Ответы [ 5 ]

6 голосов
/ 18 декабря 2008

Необходимость цепочки наследования, как правило, сомнительна.

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

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

Тем не менее, если я пишу библиотеку, и это является частью моего API / Framework, я обычно буду включать "реализацию по умолчанию", которая может использоваться в качестве базового класса. Он будет реализовывать методы интерфейса наивным, общим способом, где это возможно, и оставит остальное наследникам для реализации / переопределения по мере необходимости.

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

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

2 голосов
/ 18 декабря 2008

вам нужен интерфейс; вам может понадобиться или не понадобиться абстрактный класс.

в общем, если вы можете обеспечить некоторое полезное поведение в базовом классе, то укажите базовый класс; если базовый класс не завершен сам по себе, то сделайте его абстрактным (MustInherit на языке VB)

в противном случае достаточно интерфейса

1 голос
/ 18 декабря 2008

Вы также можете просто использовать интерфейсы. Нет причин использовать абстрактный класс.

public interface Foo : IFoo
{
}

 public interface  Bar : IFoo
{
}
1 голос
/ 18 декабря 2008

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

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

Краткий ответ : убедитесь, что вы не сходите с ума от наследства.

Надеюсь, это поможет!

0 голосов
/ 18 декабря 2008

Я не совсем уверен, что это именно то, что вы ищете, но, возможно, вы хотите, чтобы все интерфейсы были удалены и сделать это:

abstract class Base
{
    public abstract string ToCMD();
}

abstract class Foo : Base { }

abstract class Bar : Base { }

Надеюсь, у вас есть другие участники в классах Foo и Bar! Это позволит вам либо ограничить свою пользовательскую коллекцию Base, либо просто использовать простой List<Base>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...