Design patterns 在策略模式中,策略能否以上下文为参数 反馈摘要

Design patterns 在策略模式中,策略能否以上下文为参数 反馈摘要,design-patterns,strategy-pattern,Design Patterns,Strategy Pattern,现在我将结束这个主题(我想不会有更多的反馈),并尝试总结我所理解的内容 使用“Context”作为我的策略的参数引入了一种应该避免的紧密耦合,并且可能会迫使我公开应该隐藏在类中的属性 为了最大限度地减少耦合,最好提供所需的值,或者至少使用接口,而不是策略的具体类型 我试图对策略模式有一个清晰的概述,我在问自己,让策略依赖于上下文是好是坏的设计 让我们来看下面的经典实现 //The strategy interface IStrategy { void Execute(); }

现在我将结束这个主题(我想不会有更多的反馈),并尝试总结我所理解的内容

  • 使用“Context”作为我的策略的参数引入了一种应该避免的紧密耦合,并且可能会迫使我公开应该隐藏在类中的属性
  • 为了最大限度地减少耦合,最好提供所需的值,或者至少使用接口,而不是策略的具体类型

  • 我试图对策略模式有一个清晰的概述,我在问自己,让策略依赖于上下文是好是坏的设计

    让我们来看下面的经典实现

    //The strategy
    interface IStrategy  
    {  
      void Execute();  
    }  
    
    class ConcreteStrategyA : IStrategy
    {
      public void Execute()
      {
        Console.WriteLine( "Called ConcreteStrategyA.Execute()" );
      }
    }
    
    class ConcreteStrategyB : IStrategy
    {
      public void Execute()
      {
        Console.WriteLine( "Called ConcreteStrategyB.Execute()" );
      }
    }
    
    //The context
    class Context
    {
      IStrategy strategy;
    
      // Constructor
      public Context(IStrategy strategy)
      {
        this.strategy = strategy;
      }
    
      public void UpdateContext(IStrategy strategy)
      {
        this.strategy = strategy;
      }
    
      public void Execute()
      {
        strategy.Execute();
      }
    }
    
    我所看到的所有例子都有非常简单的策略,这些策略采用基本参数(例如整数)。我想知道的是,如果策略使用上下文来完成工作,是否存在错误

    它会给你类似的东西

    //The strategy
    interface IStrategy  
    {  
      void Execute(Context arg);  
    }  
    
    而这一召唤将给予

    //The context
    class Context
    {
      ....
    
      public void Execute()
      {
        strategy.Execute(this);
      }
    }
    

    是否要避免这种“耦合”?还好吗?

    嗯,还好。但是我更喜欢通过strategy implementation类的构造函数将上下文传递给strategy。

    我看到您的方法的一个问题是,具体的上下文类和strategy类的实例之间存在紧密耦合。这意味着策略类只能与上下文类一起使用。避免这种情况的一种方法是使策略类依赖(或使用)一个“上下文”类将实现的接口

    编辑 此外,当策略类具有上下文类的实例时,这些类必须从上下文类显式地获取数据。这意味着在上下文类中为策略类添加getter(根据需要),以获取它们所需的数据。但是添加getter并不一定是一个好的OO实践,因为更多的getter会带来破坏封装的风险

    您可以考虑的另一种方法是不将上下文类的引用(this)传递给strategy类中的方法,而是只将所需的数据传递给strategy类

    例如,如果上下文类是这样的:(代码是Java)

    Context {
       IStrategy strategy;
       List<Integer> scores;
    
       public Context(IStrategy strategy)
       {
            this.strategy = strategy;
            scores = new ArrayList<Integer>
       }
    
       public print() {
           strategy.sort(scores);
       }
    }
    
    public interface IStrategy<Integer> {
        public void sort(List<Integer> l);
    }
    
    上下文{
    战略战略;
    列出分数;
    公共环境(IST战略)
    {
    这个。策略=策略;
    分数=新数组列表
    }
    公共印刷品(){
    策略。排序(分数);
    }
    }
    公共接口策略{
    公共无效排序(列表l);
    }
    

    在上面的代码中,Strategy类在一个通用整数列表上操作,并且不特别绑定到上下文类中。
    此外,在定义Strategy类时,还可以使用泛型方法,这样排序方法不仅适用于整数,也适用于泛型类型。

    你的代码就是你的代码,写任何对你有意义的东西。不过,我有一句忠告

    战略模式的目的是创建一系列可以互换的战略。与许多设计模式一样,它也从解耦中获益。在本例中,我们将行为与使用此类行为的类分离

    当一个策略将上下文作为一个参数时,解耦就减少了。上下文中的更改可能需要更改您的战略实施。正如前面的一张海报所指出的,最好是寻找一种使它们解耦的方法


    也就是说,只要您的目的是允许策略可互换,并且您的代码实现了这一目的,那么我看不出有什么问题。

    根据这本书,有几种方法,包括您的:


    这意味着,对于上下文的每个实例,您都有一个策略实例?如果有很多实例,这不是有点内存开销吗?它只是一个引用而不是整个对象,所以内存在这里不是问题。这就是为什么最好通过构造函数将上下文提供给实现类,这样我们就可以决定您是否需要strategy类的上下文。如果你把它放在方法中,那么它们是紧密耦合的。不管你是通过构造函数还是作为方法参数提供对上下文的访问。这两种情况都会导致策略和上下文类之间的紧密耦合。你说得对。我的观点是,在某些情况下,策略类可能不需要上下文来工作。