两种模式(模板和策略)似乎相似。模板方法有一个抽象基类,它带有一个骨架方法,可以驱动需要改变的处理。通过调用具体类提供的抽象方法来完成处理。我们通过选择具体的类来选择我们想要的变体。
例如,我们有一个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
主要区别是什么?
答案 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));
}
}