Реализовать общее поведение в альтернативе абстрактным базовым классам? - PullRequest
7 голосов
/ 19 июня 2010

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

abstract class Control;

abstract class SquareControl: Control
{
    public int SquarishProperty;
    public void SquarishMethod();
};

class Window: SquareControl;
class Button: SquareControl;

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

abstract class FlashableControl: Control
{
    public int FlashyProperty;
    public void FlashMethod();
};

class StatusBar: FlashableControl;  // but it's also a bit square too, hmm...

Так как же вы будете делиться такими реализациями между классами без использования базовых классов?

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

Я могу визуализировать агрегирующие классы, которые реализуют это поведение, но уместно ли это и есть ли подводные камни?Какие есть альтернативы?

Спасибо

Ответы [ 3 ]

3 голосов
/ 19 июня 2010

Вы можете использовать шаблон, подобный следующему:

public interface ICommonServices
{
    string SomeProperty { get; set; }

    void SomeMethod(string param);
}

public static class CommonServiceMethods
{
    public static void DoSomething(this ICommonServices services, string param)
    {
        services.SomeMethod(services.SomeProperty + ": " + param + " something extra!");
    }
}

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


EDIT

Если вы хотите, чтобы некоторые из этих методов были внутренними, вы можете изменитьшаблон, подобный следующему:

public class MyObject : IServices
{
    public string PublicProperty { get; private set; }

    string IServices.SomeProperty { get; set; }

    void IServices.SomeMethod(string param)
    {
        //Do something...
    }
}

public interface IPublicServices
{
    string PublicProperty { get; }
}

internal interface IServices : IPublicServices
{
    string SomeProperty { get; set; }

    void SomeMethod(string param);
}

internal static class ServiceMethods
{
    public static void DoSomething(this IServices services, string param)
    {
        services.SomeMethod(services.SomeProperty + ": " + param + " something extra!");
    }
}

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

3 голосов
/ 19 июня 2010

Вы можете использовать 'has-a' вместо 'is-a' и делегировать внутренний квадратный элемент управления

    class Window : Control, ISquareControl
    {
        private SquareControl square;

        public void SquareOperation()
        {
            square.SquareOperation();
        }
    }

    class SquareControl : Control, ISquareControl
    {
        public void SquareOperation()
        {
            // ...
        }
    }
0 голосов
/ 19 июня 2010

Одним из способов является использование интерфейсов и базовых классов.

Flashable сделает хороший интерфейс вместо класса.

...