策略模式与适配器模式
策略模式:把会变化的内容取出并封装起来,以便以后可以轻易地改动或扩充部分,而不影响不需要变化的其他部分;先看一个下面的例子
采用继承的方式实现不同的行为
1 import java.util.Arrays; 2 class Processor { 3 public String name() { 4 return getClass().getSimpleName(); 5 } 6 Object process(Object input) { return input; } 7 } 8 9 class Upcase extends Processor { 10 String process(Object input) { // Covariant return 11 return ((String)input).toUpperCase(); 12 } 13 } 14 15 class Downcase extends Processor { 16 String process(Object input) { 17 return ((String)input).toLowerCase(); 18 } 19 } 20 21 public class Apply { 22 public static void process(Processor p, Object s) { 23 System.out.println("Using Processor " + p.name()); 24 System.out.println(p.process(s)); 25 } 26 public static String s = "Disagreement with beliefs is by definition incorrect"; 27 public static void main(String[] args) { 28 process(new Upcase(), s); 29 process(new Downcase(), s); 30 } 31 } /* Output: 32 Using Processor Upcase 33 DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT 34 Using Processor Downcase 35 disagreement with beliefs is by definition incorrect 36 *///:~
例子中:Upcase和Downcase是变化的内容,而Apply是不变的部分。如果在项目发展过程中,需要加入一个新的行为Splitter,那么我们只需要创建一个继承Processor的
子类Splitter即可,那么Apply的process方法不需要做任何更改即可正常运行。
class Splitter extends Processor { String process(Object input) { // The split() argument divides a String into pieces: return Arrays.toString(((String)input).split(" ")); } }
上面的这种继承的方式有缺点,因为Apply的process只适用于Processor的子类,即目前Apply只能处理3种行为:Upcase、Downcase、Splitter. 下面我们采用接口的方式
来提升Apply的能力。先重写上面的例子:
public interface Processor { String name(); Object process(Object input); }
public class Apply { public static void process(Processor p, Object s) { System.out.println("Using Processor " + p.name()); System.out.println(p.process(s));//委托给 p处理。 } }
import java.util.*;
abstract class StringProcessor implements Processor{ public String name() { return getClass().getSimpleName(); } public abstract String process(Object input); public static String s = "If she weighs the same as a duck, she’s made of wood"; public static void main(String[] args) { Apply.process(new Upcase(), s); Apply.process(new Downcase(), s); Apply.process(new Splitter(), s); } } class Upcase extends StringProcessor { public String process(Object input) { // Covariant return return ((String)input).toUpperCase(); } } class Downcase extends StringProcessor { public String process(Object input) { return ((String)input).toLowerCase(); } } class Splitter extends StringProcessor { public String process(Object input) { return Arrays.toString(((String)input).split(" ")); } }
然后:我们希望Apply能处理Wash(洗衣服):
public abstract class WashProcessor implements Processor{ public String name() { return getClass().getSimpleName(); } public abstract String process(Object input);
public static void main(String[] args) {
Clothes shirt = new Clothes("shirt"); Apply.process(new DryClean(), shirt); Apply.process(new Wash(), shirt); } } class DryClean extends WashProcessor { public String process(Object input) { return "dry-clean " + ((Clothes)input).toString(); } } class Wash extends WashProcessor { public String process(Object input) { return "wash " ((Clothes)input).toString(); } }
class Clothes {
String type;
Clothes (String type) {
this.type = type;
}
public String toString(){return type;}
}
那么现在,Apply可以处理5种行为了,而且Apply可以处理更多的实现了Processor接口的行为。相比将Processor设计成基类,Processor接口的方式更具扩展性。
适配器模式:
上面的两个例子StringProcessor和WashProcessor是我们自己写的类库;但是,你有时候会遇到你无法修改的类库,例如我们有这样一个类库:
public abstract class WashBehavior {
public abstract String process(Object input); } class DryClean extends WashBehavior { public String process(Object input) { return "dry-clean " + (Clothes)input;//自动调用Clothes的toString()然后拼接"dry-clean"返回 } } class Wash extends WashBehavior { public String process(Object input) { return "wash " + (Clothes)input; } }
很明显,Apply不能直接处理DryClean、Wash;但是我们不能修改WashBehavior,让它实现Processor(那是别人的类库)。那么我们现在就需要采用适配
器模式的思想,写一个适配器(感觉就是一中介):
class WashAdapter implements Processor { WashBehavior washBehavior; public WashAdapter(WashBehavior washBehavior) { this.washBehavior = washBehavior; } public String name() {return washBehavior.getClass().getSimpleName();} public String process(Object input) { return washBehavior.process((Clothes) input);//委托washBehavior处理 } } public class WashProcessor { public static void main(String[] args) { Clothes shirt = new Clothes("shirt"); Apply.process(new WashAdapter(new DryClean()), shirt); Apply.process(new WashAdapter(new Wash()), shirt); } }
那么有了上面的适配器WashAdapter,我们就能让Apply处理我们不能修改的类库了。
可能你已经注意到,Apply的process方法和WashAdapter的process方法都采用委托的方式,即他们不自己实现处理的细节,这就有利于程序的扩展和维护。
WashAdapter又用到了java的一个很重要的代码重用方式--组合。WashAdapter通过WashBehavior引用可以重用WashBehavior里的接口,同理,WashAdapter
还可以声明更多的Behavior,然后对每个Behavior创建重载的process方法,那么通过WashAdapter,Apply的能力将更加强大。而WashAdapter的这种持有各种
Behavior引用,并通过Behavior引用使用其接口的方式就是组合。相比继承的重用(静态重用),组合这种动态重用更加利于代码的扩展和维护;但是继承作为java三大
基本特征之一,自然有其强悍之处,这里不再细述。
注:上面部分代码未经过调试,可能会存在一些错误,如果有兴趣的看官可参照上面的代码自行调试。另:本人是一java菜鸟,此文是我学习java时做的学习笔记,以防止
遗忘。如有错误之处,欢迎各位看官指正,还望各位看官勿喷。
1 import java.util.Arrays; 2 class Processor { 3 public String name() { 4 return getClass().getSimpleName(); 5 } 6 Object process(Object input) { return input; } 7 } 8 9 class Upcase extends Processor { 10 String process(Object input) { // Covariant return 11 return ((String)input).toUpperCase(); 12 } 13 } 14 15 class Downcase extends Processor { 16 String process(Object input) { 17 return ((String)input).toLowerCase(); 18 } 19 } 20 21 class Splitter extends Processor { 22 String process(Object input) { 23 // The split() argument divides a String into pieces: 24 return Arrays.toString(((String)input).split(" ")); 25 } 26 } 27 28 public class Apply { 29 public static void process(Processor p, Object s) { 30 System.out.println("Using Processor " + p.name()); 31 System.out.println(p.process(s)); 32 } 33 public static String s = "Disagreement with beliefs is by definition incorrect"; 34 public static void main(String[] args) { 35 process(new Upcase(), s); 36 process(new Downcase(), s); 37 process(new Splitter(), s); 38 } 39 } /* Output: 40 Using Processor Upcase 41 DISAGREEMENT WITH BELIEFS IS BY DEFINITION INCORRECT 42 Using Processor Downcase 43 disagreement with beliefs is by definition incorrect 44 Using Processor Splitter 45 [Disagreement, with, beliefs, is, by, definition, incorrect] 46 *///:~