数据容器与对象结合行为

时间:2011-10-24 09:45:44

标签: c# decoupling

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

为了简化图片,我有两种类型的对象,一个工作流和一个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的原因(即使逻辑上适合)是这些对象纯粹被视为数据容器,以后它们可能会受到更改,我们希望保持这些对象的存储与对象本身。

另一种选择当然是做这样的事情:

 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 个答案:

答案 0 :(得分:1)

即使WorkflowWorkflowStep都是数据容器,但将这些保留在分层度量之外并不能解决您的解耦问题。

WorkflowStep保留在Workflow的层次结构上更合乎逻辑,并且在这种情况下必须引入IoC

IoC的美丽之处在于更改WorkflowStepWorkflow中的列表的定义将是透明的,您只会考虑在IoC上注册您的类型{1}}容器。

让我举一个使用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
}

这是将接口与具体类绑定的单一位置。在世界其他地方,你只需要一个定义接口的实例。

要解析您的类型,您需要通过加载已定义的模块来创建一个Kernel类型的Ninject IKernelStandardKernel的具体实现

这就像是,

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,因为我很满意。