【问题标题】:Which design pattern fit for this scenario C#? [closed]哪种设计模式适合这种 C# 场景? [关闭]
【发布时间】:2015-12-15 03:27:53
【问题描述】:

我正在开发一个 C# MVC 应用程序。我有一个场景,我想知道哪种设计模式最适合它。

场景是:

我必须为一个实体执行一些步骤序列。喜欢:

Step-1 Entity Created
Step-2 Entity Approved
Step-3 Entity Assigned to someone
Step-4 Entity Publish
..
....

这些步骤是配置的,意味着管理员可以随时打开/关闭一些非强制性步骤。喜欢:

如果管理员关闭了第 2 步,那么在第 1 步之后我需要直接进入第 3 步。

谁能帮我确定上述场景的设计模式。

谢谢

【问题讨论】:

  • 访问者或命令链模式可能适合您。
  • 阅读 Gang of 4。实现所有这些,然后告诉我们哪个是最好的 ;)

标签: c# asp.net-mvc oop design-patterns


【解决方案1】:

在我看来,这是一个工作流程。微软有一个工作流引擎:https://code.msdn.microsoft.com/Windows-Workflow-deed2cd5

使用工作流,您可以创建 Step1、Step2、Step3,因为可以禁用和重新启用工作流操作和步骤等。

您还可以获得一个简洁的基于 xaml 的工作流设计器。我发布的链接上有示例代码。

【讨论】:

  • 这是另一篇关于在 mvc 4+ 中集成持久工作流的文章。 stevenwilliamalexander.wordpress.com/2010/11/16/…
  • 另外,如果你想用这些东西接触共享点,工作流很酷,因为你可以使用你的工作流基础工作流并在共享点中使用它们并将它们附加到列表和东西上使用列表数据贯穿您的工作流程。如果您不使用共享点(曾经),那么考虑只是滚动您自己的状态机,正如@Andrew 为简单起见所建议的那样。工作流程很好,但有很多东西需要学习和实施,而且它们可能会变得非常复杂。
【解决方案2】:

我想到的第一个设计模式是State。您可以让每个状态都有一个GetNextState()(或类似的)方法,该方法进行必要的检查并返回相应的以下状态。

【讨论】:

    【解决方案3】:

    也许你可以试试Template Method Pattern 加上一些状态参数。

    abstract class AbsFoo {
        public abstract void Step1();
        public abstract void Step2();
        public abstract void Step3();
        public abstract void Step4();
    
        public void process(bool doStep1, 
                            bool doStep2,
                            bool doStep3,
                            bool doStep4) {
            if (doStep1) Step1();
            if (doStep2) Step2();
            if (doStep3) Step3();
            if (doStep4) Step4();
        }
    }
    
    class ConcreteFoo : AbsFoo {
        public override void Step1() {
            Console.WriteLine("Do something in step 1.");
        }
        public override void Step2()
        {
            Console.WriteLine("Do something in step 2.");
        }
        public override void Step3()
        {
            Console.WriteLine("Do something in step 3.");
        }
        public override void Step4()
        {
            Console.WriteLine("Do something in step 4.");
        }
    }
    

    然后在客户端类中,就可以调用基类中的方法了。

    class Client {
        static void Main() {
            AbsFoo foo = new ConcreteFoo();
    
            foo.process(true, false, true, true);
    
            Console.ReadKey();
        }
    }
    

    但是,如果状态越来越多,您可以考虑将State Pattern 与此结合。

    【讨论】:

    • 为什么需要将doStepN 传递给process 方法?以后如果要添加step5、step6、step7,也需要修改process方法。 如果您不想执行任何步骤,只需在具体类中将其留空即可。
    • @kienct89 因为通过将doStepN 传递给process 方法,可以动态决定在程序运行期间调用哪个方法。例如,我可以根据用户输入设置doStepN。如果在具体类中将方法留空,则程序运行时无法调用。
    【解决方案4】:

    希望我能正确理解您的问题;

    您可能对事件驱动编程感兴趣; https://msdn.microsoft.com/en-us/library/awbftdfh.aspx

    您可以将“步骤”代码设计为模块,允许从“控制中心”打开和关闭标志,并根据需要采取的步骤引发事件。

    这也为多线程步骤留出了空间(如果您选择开发模块,并且可以保证它们是正交的)。

    【讨论】:

      【解决方案5】:

      我建议你在这种情况下使用template method 设计模式。

      确保执行顺序,提供关闭一个或多个步骤的能力。

      参考:http://www.dofactory.com/net/template-method-design-pattern

      【讨论】:

        【解决方案6】:

        对我来说,这听起来像是一种状态机类型的情况,其中步骤是您的状态对象,并且每个状态可能有多个基于条件(例如当前打开的选项)的退出转换。然后,State 将代替 MVC 中的 C。

        可以在此处with a focus on game programming 找到有关该模式的讨论,并提供其他示例。

        状态模式本质上将允许您创建一个图表,更重要的是,允许为图表的每条边分配行为,这将导致该边被遵循。

        所以在你的情况下,可以在我刚刚提出的这个组合方案中定义图表:

        [state] => [transition-to] (condition)
        1 => 3 (if opt_go_to_3 == true)
        1 => 2 
        2 => 3
        2 => 5 (if some_other_optioon == true)
        2 => 3
        ... (etc)
        

        现在您的代码已经很好地客观化了,但仍然非常灵活。当涉及到你需要根据条件运行的行为时。

        现在如果在你的 MVC 方案中使用这个状态对象作为控制器,它实际上都非常适合。

        您的状态机的当前状态可以根据一些模型数据在进入时创建新视图。

        谈到该模型数据,将其硬编码到状态机基础架构中并不是一个好主意,因为它会使一切变得非常笨拙且非常快速。

        请考虑使用黑板或留言板类型的界面。这个想法说每个状态都应该有一个接口来向对象写入消息。

        这可以通过使用 C# 中的委托、在创建对象时将对象传递给每个状态或任何其他模式来完成,该模式将使机器中的所有状态都可以访问此“全局”资源。

        板的想法是,一个州可以向它发布数据,例如一些计算的结果或一些用户输入的值。然后稍后运行的另一个状态可能会选择读取消息以获得有用的值。

        【讨论】:

          猜你喜欢
          • 2011-02-19
          • 2023-03-10
          • 2012-10-29
          • 1970-01-01
          • 1970-01-01
          • 2017-07-04
          • 2011-02-27
          • 1970-01-01
          相关资源
          最近更新 更多