【问题标题】:What is the difference between template pattern and strategy pattern?模板模式和策略模式有什么区别?
【发布时间】:2017-06-07 22:59:09
【问题描述】:

这两种模式(模板和策略)看起来很相似。模板方法有一个抽象基类和一个驱动需要变化的处理的骨架方法。通过调用具体类提供的抽象方法来完成处理。我们通过选择具体的类来选择我们想要的变体。

例如,我们有一个 Report 类和一个继承自 Report 的 HTMLReport 类。我们的Report 类可能如下所示:

class Report
def initialize
@title = 'Monthly Report'
@text = ['Things are going', 'really really well']
end

def output_report
output_start
output_head
output_body_start
output_body
output_body_end
output_end
end


def output_body
@text.each do |line|
output_line(line)
end

def output_start
raise StandardError
end

def output_head
raise 'This needs to be implemented by the concrete class'
end
...
end

以及我们实际的具体类:

class HTMLReport < Report
def output_start
puts('<html>')
end

def output_head
puts('    <head>')
...
end

...
end

实际使用:

report = HTMLReport.new
report.output_report

关键是抽象类为算法的可变部分调用其他方法,然后我们可以子类化(在这种情况下通过 Ruby 继承),然后处理实际实现。

但是,有一些缺点(根据 Russ Olsen 的说法): - 使用继承 - 限制了运行时的灵活性...一旦我们选择了特定版本的算法,就很难改变主意。

所以,策略模式: - 取出烦人的代码块并将其隔离在自己的类中。然后创建一个完整的类族,每个变体一个。

例子:

class Formatter
def output_report(title, text)
raise 'Abstract Method called'
end
end

class HTMLFormatter < Formatter
def output_report(title, text)
puts('<html>')
puts('   <head>')
puts("   <title>#{title}</title>")
puts('    </head>')
...
end

现在我们的Report 类看起来像这样:

class Report
attr_reader :title, :text
attr_accessor :formatter

def initialize(formatter)
@title = 'Monthly Report'
@text = ['Things are going', 'really, really well.']
@formatter = formatter
end

def output_report
@formatter.output_report(@title, @text)
end
end

所以,如果我错了,请纠正我,因为这些策略都有相同的接口,我们可以在 Report 类中委托给它们。 Report 类被那些 GOF 人称为 context

但这如何让我们在运行时切换策略?我们还是这样称呼他们吧?

report = Report.new(HTMLFormatter.new)
report.output_report

主要区别是什么?

【问题讨论】:

  • 如果你想改变模板方法版本中的格式,你必须创建一个全新的报告(因为你需要一个不同的子类)。在策略版本中,您只需为现有报告分配一个新的格式化程序。

标签: design-patterns


【解决方案1】:

模板模式算不上什么模式。它简单地描述了我们都知道的多态性的基本原理。另一方面,策略模式为“功能”/“策略”定义了一个通用接口,可以在运行时换出。以下是 Java 中的策略模式示例(抱歉,不熟悉 Ruby):

免责声明:不是我的代码,很好的例子。

public interface Strategy {
   public int doOperation(int num1, int num2);
}

public class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
     return num1 + num2;
   }
}

public class OperationSubstract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}

// Using this Context and common Strategy interface, we can utilize any operation
// we want.
public class Context {
   private Strategy strategy;

   public Context(Strategy strategy){
       this.strategy = strategy;
   }

   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

public class StrategyPatternDemo {

    public static void main(String[] args) {

       // Implement any Operation that implements Strategy interface
       Context context = new Context(new OperationAdd());       
       System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

       context = new Context(new OperationSubstract());     
       System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

       context = new Context(new OperationMultiply());      
       System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
   }
}

【讨论】:

  • 我对 Java 不太熟悉,介意带我看一下吗?
  • 当然,我这周刚开始学习 Ruby,所以不太清楚如何在 Ruby 中做到这一点,但我确信可以做到。创建从名为“Strategy”的基类继承的“Add”、“Subtract”类,并在名为doOperation 的方法中完成它们的工作。使用名为execute 的方法创建另一个名为“Context”的类。在这个execute 方法中,“上下文”将调用这个doOperation 方法。创建 Context 时,将使用要执行的操作类型创建它,例如:Context.new( new Add ) - 如果这甚至是有效的 Ruby。
  • 或者我的意思是,介意通过您的 Java 与我交谈吗?我的生锈了......这又是什么:`main(String [] args)`和private Strategy strategypublic int doOperation(int num1, int num2) { return num1 - num2; }
  • 我只是做了。整个应用程序从main(String[] args) 开始。它创建一个new Context 对象,传入new OperationAdd 对象。由于OperationAdd 继承自Strategy 并实现doOperation,如果您查看Context 类,它所要做的就是调用实例变量strategy.doOperation(num1, num2)。这是因为保证所有Strategy都实现了这个接口。
猜你喜欢
  • 2010-10-14
  • 2010-10-11
  • 2010-10-02
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多