简体   繁体   English

模板模式和策略模式有什么区别?

[英]What is the difference between template pattern and strategy pattern?

The two patterns (template and strategy) seem similar. 两种模式(模板和策略)似乎相似。 The template method has an abstract base class with a skeletal method that drives the processing that needs to vary. 模板方法具有一个抽象的基类,该类具有一个骨架方法,该骨架方法驱动需要变化的处理。 The processing is done by calling abstract methods that are supplied by the concrete classes. 通过调用由具体类提供的抽象方法来完成处理。 We select the variation that we want by picking the concrete classes. 我们通过选择具体的类来选择所需的变体。

For example, we have a Report class, and an HTMLReport class that inherits from Report. 例如,我们有一个Report类,以及一个从Report继承的HTMLReport类。 Our Report class could look like this: 我们的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

and our actual concrete class: 和我们实际的具体课程:

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

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

...
end

Actual use: 实际用途:

report = HTMLReport.new
report.output_report

The key thing is that the abstract class calls other methods for the variable parts of the algorithm, which we can then subclass (in this case through Ruby inheritance) and then work on the actual implementation. 关键是抽象类为算法的可变部分调用其他方法,然后我们可以将其子类化(在这种情况下是通过Ruby继承),然后进行实际实现。

However, some drawbacks (according to Russ Olsen): - uses inheritance - limits runtime flexibility... once we select a particular version of the algo, changing our mind is hard. 但是,有些缺点(根据Russ Olsen的说法):-使用继承-限制了运行时的灵活性...一旦选择了特定版本的算法,就很难改变主意。

So, the strategy pattern: - take out the annoyingly varying chunk of code and isolate it in its own class. 因此,策略模式:-删除烦人的变化代码块并将其隔离在自己的类中。 Then create a whole family of classes, one for each variation. 然后创建一整个类家族,每个类一个。

Example: 例:

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

Now our Report class looks like this: 现在,我们的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

So, correct me if I'm wrong, it looks like since the strategies all have the same interface, we can just delegate to them in the Report class. 因此,如果我错了,请纠正我,由于策略都具有相同的接口,因此我们可以在Report类中将它们委派给他们。 The Report class is called the context by those GOF people. 这些GOF人员将Report类称为context

but how does this allow us to switch strategies at runtime? 但这如何使我们在运行时切换策略? We still call them like this right? 我们还是这样称呼他们吗?

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

What are the main differences? 主要区别是什么?

A template pattern isn't much of a pattern. 模板模式并不是很多模式。 It simply describes what we all know to be the fundamentals of polymorphism. 它只是描述了众所周知的多态性基础。 The Strategy Pattern on the other hand defines a common interface for "functions"/"strategies" which can be swapped out at run time. 另一方面,策略模式为“功能” /“策略”定义了一个公共接口,可以在运行时将其交换出来。 Here's an example of the Strategy Pattern in Java (sorry, not well versed in Ruby): 这是Java中的策略模式的示例(很抱歉,不熟悉Ruby):

Disclaimer: Not my code, great example. 免责声明:不是我的代码,很好的例子。

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));
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM