策略模式:把会变化的内容取出并封装起来,以便以后可以轻易地改动或扩充部分,而不影响不需要变化的其他部分;先看一个下面的例子

采用继承的方式实现不同的行为

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 *///:~