Базовый класс в C # ... который может быть унаследован от как интерфейс? - PullRequest
2 голосов
/ 27 ноября 2011

Мне нужно реализовать базовое поведение для многих классов.Для примера предположим, что это своего рода поведение при рисовании: существует много различных типов объектов, которые могут быть нарисованы, и всем им нужно несколько атрибутов и некоторый общий код для реализации процесса рисования.Допустим, я поместил эту общую часть в класс Drawable.

Проблема в том, что эти разные классы могут расширять другие классы, поэтому я не могу их наследовать от Drawable.Очевидным решением было бы использование интерфейса (IDrawable), но тогда я не смог реализовать в нем никакого кода;другое решение, которое я могу придумать, - использовать композицию, создав класс DrawAction, для которого будут созданы все мои классы, но для этого потребуется, чтобы я поместил один и тот же код (если только пару строк) во все классы, которые мне нужно сделатьвытяжка.

Может кто-нибудь подсказать, пожалуйста, как это сделать?Благодарю.

Ответы [ 5 ]

5 голосов
/ 27 ноября 2011

Вы можете создать экземпляр класса DrawAction, а затем просто внедрить его в другие классы, используя внедрение зависимостей конструктора, а не явно создавать его экземпляры для каждого класса, это также дает вам менее связанный дизайн:

IDrawAction drawAction = new DrawAction();
var drawable = new Drawable(drawAction);

public class Drawable
{
    public Drawable(IDrawAction drawAction)
    {
    }
}
4 голосов
/ 27 ноября 2011

Это может быть ситуация для композиции , а не наследования.

Вы можете реализовать поведение рисования в одном классе, а затем иметь все классы, которым оно требуется, с указанием ссылки на него.

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

В зависимости от вашей ситуации, если определенным типам объектов всегда требуется определенный тип алгоритма рисования, выбор класса рисования может быть автоматизирован с использованием контейнера IoC, например StructureMap или Единство .

Вот пример шаблона стратегии из DoFactory

2 голосов
/ 27 ноября 2011

Вы можете создать методы расширения для IDrawable:

public static class DrawableExtensions
{
    public static int CalculateSize(this IDrawable drawable)
    {
         return drawable.Width * drawable.Height;
    }
}

Таким образом эти методы будут отображаться на интерфейсе IDrawable:

IDrawable d = new Circle();

int size = d.CalculateSize();

Недостатком является то, что методы расширения являются статическими, и вы не можете их переопределить.

1 голос
/ 28 ноября 2011

Похоже, что шаблон Декоратор может быть подходящим для того, что вы пытаетесь достичь.

См. Статью в Википедии «Шаблон декоратора»

  • Вместо того чтобы пытаться унаследовать общую логику "Рисование", поместите общую логику в другой класс, т. Е. "Draw * er *"
  • Когда объект должен быть нарисован, передайте его соответствующему Draw * er * (или сделайте Draw * er * для него)
  • Вы все еще можете найти интерфейс IDrawable полезным, так что код Draw * er * может быть написан для известного интерфейса.
  • Вы можете получить несколько реализаций Draw * er * (в этом случае вам нужно будет обрабатывать динамический выбор соответствующего Drawer для каждого рисуемого объекта)
1 голос
/ 27 ноября 2011

C # не поддерживает множественное наследование. Стоп. Тебе этого не сделать. Вы говорите о "Mixins" ... которые до сих пор не поддерживаются в C #.

Однако есть несколько альтернатив, которые вы можете использовать.

Проще всего использовать класс Mixin, который вы можете добавить в качестве поля во все ваши классы. Например ...

public class DrawerMixin
{
    public void DrawRectangle() { ... }
}

public class MyClass1 : Component
{
    public DrawerMixin Drawer { get; private set; }

    public MyClass1()
    {
        this.Drawer = new DrawerMixin(this);
    }

    public MyClass1(DrawerMixin drawer)
    {
        this.Drawer = drawer;
    }

    public void MyFunc()
    {
        ...
        this.Drawer.DrawRectangle();
    }
}
...