#c# #decoupling
#c# #развязка
Вопрос:
Я пишу решение для хранения данных для иерархии рабочих процессов.
Чтобы упростить картину, у меня есть 2 типа объектов: рабочий процесс и WorkflowStep.
Несмотря на то, что WorkflowStep иерархически подчиняется рабочему процессу, рабочий процесс не агрегирует WorkflowStep, потому что мы рассматриваем эти объекты как просто контейнеры данных.
Итак, это оставляет меня со следующими классами:
public class Workflow : Node {
public string UID;
public string parentID;
}
public class WorkflowStep : Node {
public string UID;
public string parentID;
}
public class WorkflowEngine {
public void Store(Workflow wf) {
}
public void Store(WorkflowStep wfs) {
}
}
Причина отказа от агрегирования WorkflowStep внутри Workflow (хотя логически это подходит) заключается в том, что эти объекты рассматриваются исключительно как контейнеры данных, и в дальнейшем они могут быть изменены, и мы хотим, чтобы хранилище этих объектов было отделено от самих объектов.
Другой альтернативой, конечно, было бы сделать что-то вроде этого:
public class Workflow : Node {
public List<WorkflowStep> steps;
public string UID;
public string parentUID;
public void Store() { }
}
public class WorkflowStep : Node {
public string UID;
public string parentID;
public void Store() { }
}
Каковы плюсы и минусы любого подхода? Есть ли какая-либо литература, в которой говорится об обоих проектах?
Комментарии:
1. Это зависит.. действительно.. это зависит от того, как обрабатываются данные и как все вписывается в общую картину
Ответ №1:
Несмотря Workflow
на то, что и WorkflowStep
оба являются контейнерами данных, но их исключение из иерархических мер не решает проблему развязки.
Более логично придерживаться WorkflowStep
иерархии Workflow
и обходиться с развязкой, которую вы должны ввести IoC
в этом случае.
Прелесть IoC
в том, что изменение определений WorkflowStep
, которые являются списком в Workflow
классе, будет просто прозрачным, когда вы будете рассматривать только регистрацию своих типов в своем IoC
контейнере.
Позвольте мне привести вам пример с Ninject
IoC
контейнерной платформой.
Определите интерфейсы и соответствующим образом реализуйте свои контейнеры данных:
public interface IWorkflow {
string UID { get; set; }
string parentID { get; set; }
IList<IWorkflowStep> Steps { get; set; }
}
public interface IWorkflowStep {
string UID { get; set; }
string parentID { get; set; }
}
public class Workflow : IWorkflow, Node {
public string UID { get; set; };
public string parentID { get; set; };
public IList<IWorkflowStep> Steps { get; set; }
}
public class WorkflowStep : IWorkflowStep, Node {
public string UID { get; set; };
public string parentID { get; set; };
}
И теперь модуль Ninject будет:
public class WorkflowModule : NinjectModule
{
#region Overrides of NinjectModule
public override void Load()
{
Bind<IWorkflow>().To<Workflow>();
Bind<IWorkflowStep>().To<WorkflowStep>();
Bind<IList>().To<List>();
}
#endregion
}
Это единственное место, где вы связываете свои интерфейсы с конкретными классами. И остальной мир, вы просто запрашиваете экземпляр определенного интерфейса.
Чтобы разрешить ваш тип, вам необходимо создать Ninject Kernel
, который является IKernel
типом и конкретной реализацией StandardKernel
, загрузив определенный вами модуль.
Что-то вроде,
var kernel = new StandardKernel(new WorkflowModule());
Теперь все, что вам нужно сделать, это разрешить желаемый интерфейс, например:
IWorkflow workflow = kernel.Get<IWorkflow>();
IWorkflowStep workflowStep = kernel.Get<IWorkflowStep>();
Прелесть здесь в том, что вам не нужно беспокоиться о вашей конкретной реализации, которая очень тесно связана с вашей системой. Это просто интерфейс, с которым вы будете иметь дело, а остальное — забота о вашей IoC
контейнерной реализации.
Поскольку вы больше беспокоитесь о том, что реализация WorkflowStep
должна быть изменена, а не связана Workflow
. Я думаю, это то, где IoC
начинается игра.
Пожалуйста, обратите внимание, что вы можете использовать любой IoC
контейнерный фреймворк, такой как Unity, Spring.NET, StructureMap и т.д. Я использовал Ninject, потому что мне это удобно.