Быстрый дизайн интерфейса и запах кода

public class StepClause
{
    public NamedStepClause Action1() {}

    public NamedStepClause Action2() {}
}

public class NamedStepClause : StepClause
{
    public StepClause Step(string name) {}
}

В основном я хочу смочь сделать что-то вроде этого:

var workflow = new Workflow().Configure()
    .Action1()
    .Step("abc").Action2()
    .Action2()
    .Step("def").Action1();

Так, некоторые "шаги" называют, и некоторые не.

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

Я попробовал несколько вещей заставить это находиться лучше со мной. Я пытался выгнать вещи с квартиры к интерфейсам, но затем проблема просто переместилась от бетона до интерфейсов - INamedStepClause все еще должен произойти из IStepClause, и IStepClause должен возвратить INamedStepClause, чтобы смочь назвать Шаг (). Я мог также сделать Шаг () частью абсолютно отдельного типа. Затем у нас нет этой проблемы, и мы имели бы:

var workflow = new Workflow().Configure()
    .Step().Action1()
    .Step("abc").Action2()
    .Step().Action2()
    .Step("def").Action1();

Который в порядке, но я хотел бы сделать неродное именование дополнительным, если это возможно.

Я нашел это другое сообщение на, ТАКИМ ОБРАЗОМ, здесь, который выглядит интересным и многообещающим. Каковы Ваши мнения? Я думал бы, что исходное решение абсолютно недопустимо или является этим?

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

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

6
задан Community 23 May 2017 в 11:47
поделиться

1 ответ

Я дам вам два варианта.

Вариант A

var a = new A.NamedStepClause();

a.Action1()
    .Step("abc").Action2()
    .Action2()
    .Step("def").Action1();


namespace A
{
    public class StepClause<SC> where SC : StepClause<SC>
    {
        public SC Action1() { return null; }
        public SC Action2() { return null; }
    }

    public class NamedStepClause : StepClause<NamedStepClause>
    {
        public NamedStepClause Step(string name) { return null; }
    }
}

Вариант B

var b = new B.StepClause();

b.Action1()
    .Step("abc").Action2()
    .Action2()
    .Step("def").Action1();

namespace B
{
    public class StepClause
    {
        public StepClause Action1() { return null; }
        public StepClause Action2() { return null; }
    }

    public static class StepClauseExtensions
    {
        public static StepClause Step(this StepClause @this, string name)
        { return null; }
    }
}

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

Удачи!

9
ответ дан 10 December 2019 в 02:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: