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

时间:2017-06-07 14:30:38

标签: design-patterns

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

例如,我们有一个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

主要区别是什么?

1 个答案:

答案 0 :(得分: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));
   }
}