Нужно ли нам оборачивать компоненты при использовании композитинга? - PullRequest
0 голосов
/ 28 сентября 2018

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

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

Например:

interface IFoo
{
    void DoFoo();
}

interface IBar
{
    void DoBar();
}

interface IBaz
{
    void DoBaz();
}

class DefaultFoo()
{
    public void Do() { /* Shared logic */ }
}

class DefaultBar()
{
    public void Do() { /* Shared logic */ }
}

class FooBarBaz1 : IFoo, IBar, IBaz
{
    DefaultFoo defaultFoo = new DefaultFoo();
    DefaultBar defaultBar = new DefaultBar();

    public void DoFoo() { defaultFoo.Do(); }
    public void DoBar() { defaultBar.Do(); }
    public void DoBaz() { /* FooBarBaz1 specific IBaz implementation */ }
}

class FooBarBaz2 : IFoo, IBar, IBaz
{
    DefaultFoo defaultFoo = new DefaultFoo();

    public void Foo() { defaultFoo.Do(); }
    public void Bar() { /* FooBarBaz2 specific IBar implementation */ }
    public void Baz() { /* FooBarBaz2 specific IBaz implementation */ }
}

// More ForBarBazX classes...

В классах FooBarBaz1 и FooBarBaz2 мы полностью переносим экземпляр DefaultFoo всоздайте у общественности впечатление, что FooBarBaz1 и FooBarBaz2 выполняют работу, а просто делегируют ее.

Проблема в том, что если у вас есть большое количество классов, которые должны реализоватьИнтерфейс и / или интерфейс имеет много методов, в результате вы вынуждены написать много «бесполезного» кода делегирования.

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

Вместо этого мы бы:

interface IFoo
{
    DefaultFoo Foo { get; }
}

interface IBar
{
    DefaultBar Bar { get; }
}

interface IBaz
{
    DefaultBaz Baz { get; }
}

class DefaultFoo()
{
    public virtual void Do() { /* Shared logic */ } // Note the virtual.
}

class DefaultBar()
{
    public virtual void Do() { /* Shared logic */ } // Note the virtual.
}

class FooBarBaz1 : IFoo, IBar, IBaz
{
    private class SpecificBaz : DefaultBaz
    {
        public override void DoBaz() { /* Specific logic */ }
    }

    public DefaultFoo Foo { get; private set; }
    public DefaultBar Bar { get; private set; }
    public DefaultBaz Baz { get; private set; }

    public FooBarBaz1()
    {
        Foo = new DefaultFoo();
        Bar = new DefaultBar();
        Baz = new SpecificBaz();
    }
}

class FooBarBaz2 : IFoo, IBar, IBaz
{
    private class SpecificBar : DefaultBar
    {
        public override void Bar() { /* Specific logic */ }
    }

    private class SpecificBaz : DefaultBaz
    {
        public override void Baz() { /* Specific logic */ }
    }

    public DefaultFoo Foo { get; private set; }
    public DefaultBar Bar { get; private set; }
    public DefaultBaz Baz { get; private set; }

    public FooBarBaz1()
    {
        Foo = new DefaultFoo();
        Bar = new SpecificBaz();
        Baz = new SpecificBaz();
    }
}

Чем вместо:

ForBarBaz1 fooBarBaz = new ForBarBaz1();
fooBarBaz.Foo();
fooBarBaz.Bar();
fooBarBaz.Baz();

Можно получить доступ к открытым компонентам:

ForBarBaz1 fooBarBaz = new ForBarBaz1();
fooBarBaz.Foo.Do();
fooBarBaz.Bar.Do();
fooBarBaz.Baz.Do();

Что вы думаете об этом?Похоже, что он сохраняет модульность, избегая большого количества «бесполезного» упаковочного кода.

PS: я спрашиваю это для C #, но я думаю, что это также применимо к некоторым другим языкам.

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