8

我正在处理的应用程序处理工作项。根据工作项的状态,有许多可用的操作。“完成”“取消”“重新分配”等...

为了提供操作的功能,我目前有一个看起来像这样的界面......

public interface IActionProvider{
    public void Complete(WorkItem workItem);
    public void Cancel (WorkItem workItem);
    public void Reassign(WorkItem workItem);
}

然后根据工作项的其他细节,我有了接口的具体实现。举个例子……

public class NormalActionProvider :IActionProvider
{
    ...
}

public class UrgentActionProvider : IActionProvider
{
   ....
}

问题是,如果我想添加一个新动作,比如说......“委托”我必须更新接口,这当然会对所有实现产生影响。

这是否违反了打开/关闭原则?你能推荐一个可能对我有帮助的设计模式或重构吗?

4

5 回答 5

11

看起来命令模式是合适的。您可以修改/添加更多命令。命令类与主程序分离。

public interface IActionProvider{
    public void execute(WorkItem item,ActionType actionType);
}

ActionType 代表 Complete、Cancel 等。您可以继续添加更多动作类型和插件适当的命令类。

于 2011-08-08T03:29:57.103 回答
3

您始终可以将装饰器添加到 IActionProvider 接口(遵循装饰器设计模式)。

于 2011-08-08T03:16:18.030 回答
0

这取决于你真正想用你的IActionProvider. 如果你真的想让每个实现都必须能够执行你认为重要的所有操作,那么这应该是它们实现的接口的一部分。如果提前精心规划接口,它们就可以发挥最佳效果,这样它们就不必不断地改变。

但听起来您不一定希望所有提供者都执行所有操作。我需要了解更多细节才能给出好的建议,但一个例子是让提供者针对一种事件总线初始化自己。他们可以订阅他们关心的那些事件,并且只针对对特定实现有意义的事件执行操作。

于 2011-08-08T03:06:37.987 回答
0

“取决于工作项的状态”,带来了状态设计模式

无论哪种方式,您都必须重构界面并最终破坏客户合同。

如果我正确理解了您的问题,那么您有一个 WorkItemProcessor,其状态会根据发送给它的 WorkItem 发生变化。

因此你的 WorkItemProcessor 变成

// Context
    public class WorkItemProcessor
    {
        public IState CurrentState { get; set; }

        public WorkItemProcessor(IState initialState)
        {
            CurrentState = initialState;
        }

        public void Process(WorkItem workItem)
        {
            CurrentState.Handle(this, workItem);
        }
    }

然后我们定义 WorkItemProcessor 可能处于的多个状态

// State Contract
    public interface IState
    {
        void Handle(WorkItemProcessor processor, WorkItem item);
    }

    // State One
    public class CompleteState : IState
    {
        public void Handle(WorkItemProcessor processor, WorkItem item)
        {
            processor.CurrentState = item.CompletenessConditionHoldsTrue ? (IState) this : new CancelState();
        }
    }

    // State Two
    public class CancelState : IState
    {
        public void Handle(WorkItemProcessor processor, WorkItem item)
        {
            processor.CurrentState = item.CancelConditionHoldsTrue ? (IState) this : new CompleteState();
        }
    }

假设您的 WorkItem 看起来像

 // Request
    public class WorkItem
    {
         public bool CompletenessConditionHoldsTrue { get; set; }

         public bool CancelConditionHoldsTrue { get; set; }
    }

把它们放在一起

static void Main()
    {
      // Setup context in a state 
      WorkItemProcessor processor = new WorkItemProcessor(new CancelState());

      var workItem1 = new WorkItem {  CompletenessConditionHoldsTrue = true };
      var workItem2 = new WorkItem {  CancelConditionHoldsTrue = true };

      // Issue requests, which toggles state 
      processor.Process(workItem1);
      processor.Process(workItem2);

      Console.Read();
    }

希望这能让你更接近。干杯。

于 2011-08-08T04:46:28.937 回答
0

我也会选择命令模式。作为一种增强,您可以将它与抽象工厂方法结合起来,这样您就可以为每个命令类拥有一个工厂类,并且所有这些工厂都实现了一个通用的工厂接口。

例如:

// C#
public interface ICommand { void Execute(); }

public interface ICommandFactory { ICommand Create(); }

public class CommandFactoryManager
{
    private IDictionary<string, ICommandFactory> factories;

    public CommandFactoryManager()
    {
        factories = new Dictionary<string, ICommandFactory>();
    }

    public void RegisterCommandFactory(string name, ICommandFactory factory)
    {
        factories[name] = factory;
    }

    // ...
}

这样,您可以动态注册新的命令工厂。例如,您可以在运行时加载 DLL 并使用反射获取所有实现 ICommandFactory 接口的类,并且您有一个简单的插件系统。

于 2011-08-08T06:52:02.410 回答