数据容器与对象与行为相结合

发布于 2024-12-11 16:59:13 字数 980 浏览 5 评论 0原文

我正在为工作流层次结构编写一个存储解决方案。

为了简化图片,我有两种类型的对象:Workflow 和 WorkflowStep。

尽管 WorkflowStep 按层次结构位于 Workflow 之下,但 Workflow 不会聚合 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) {
    }
}

不在 Workflow 中聚合 WorkflowStep 的原因(即使逻辑上适合)是这些对象纯粹被视为数据容器,它们可能会在以后发生更改,并且我们希望保留存储这些对象与对象本身解耦。

当然,另一种选择是这样做:

 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() { }
}

这两种方法的优点和缺点是什么?有没有任何文献讨论这两种设计?

I am writing a storage solution for a workflow hierarchy.

To simplify the picture I have 2 types of objects, a Workflow and a WorkflowStep.

Even though WorkflowStep comes hierarchically under the Workflow, the Workflow does not aggregate WorkflowStep because we view these objects as just data containers.

So this leaves me with the following classes:

 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) {
    }
}

The reasoning for not aggregating WorkflowStep inside Workflow (even though logically that fits) is that these objects are purely viewed as data containers and they may be subject to changes later on and we want to keep the storage of these objects decoupled from the objects themselves.

The other alternative of course would be to do something like this:

 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() { }
}

What are the pros and cons of either approach? Is there any literature that talks about both the designs?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苹果你个爱泡泡 2024-12-18 16:59:13

尽管 WorkflowWorkflowStep 都是数据容器,但将它们与分层措施分开并不能解决解耦问题。

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容器框架,例如UnitySpring.NETStructureMap > 等等。我使用 Ninject 因为我对它很满意。

Even though Workflow and WorkflowStep are both data containers but keeping these aside from hierarchical measures doesn't solve your decoupling issue.

It is more logical to keep WorkflowStep on hierarchy of Workflow and to get along with decoupling you must introduce IoC in this case.

The Beauty of IoC is that changing the definitions of WorkflowStep which is a list in Workflow class will be just transparent where you will only be considering to register your types on your IoC container.

Let me put you on an example with Ninject IoC container framework.

Define interfaces and implement your data containers accordingly:

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; };
}

And now, the Ninject module be:

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
}

This is the single place where you bind your interfaces with concrete classes. And rest of the world, you just ask for an instance of defined interface.

To resolve your type, you need to create a Ninject Kernel which is an IKernel type and a concrete implementation of StandardKernel by loading your defined module.

Which is something like,

var kernel = new StandardKernel(new WorkflowModule());

Now, all you have to do is resolve your desired interface, like:

IWorkflow workflow = kernel.Get<IWorkflow>();
IWorkflowStep workflowStep = kernel.Get<IWorkflowStep>();

The beauty here is, you don't need to worry about your concrete implementation and which is very tightly coupled within your system. Its just the interface you will be dealing with and rest are the worries of your IoC container implementation.

As you are more worried about the implementation of WorkflowStep to be changed and not coupling with Workflow. I guess, this is where IoC comes to play.

Please be noted that, you can use any IoC container framework like Unity, Spring.NET, StructureMap and etc. I used Ninject because I am comfortable with it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文