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();
Который в порядке, но я хотел бы сделать неродное именование дополнительным, если это возможно.
Я нашел это другое сообщение на, ТАКИМ ОБРАЗОМ, здесь, который выглядит интересным и многообещающим. Каковы Ваши мнения? Я думал бы, что исходное решение абсолютно недопустимо или является этим?
Между прочим, те методы действия возьмут предикаты и функторы, и я не думаю, что хочу взять дополнительный параметр для именования шага там.
Точка всего этого для меня, должен только определить эти методы действия в одном месте и одном месте только. Таким образом, решения из ссылки, на которую ссылаются, с помощью дженериков и дополнительных методов, кажется, лучшие подходы до сих пор.
Я дам вам два варианта.
Вариант 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; }
}
}
Оба варианта компилируются и предоставляют удобный интерфейс, который вы ищете. Я больше склоняюсь к варианту А, поскольку он дает вам доступ к внутренней работе класса. Использование методов расширения означает, что вам может потребоваться какой-то внешний доступ к вашему классу, что нарушит инкапсуляцию.
Удачи!