策略模式与适配器模式

时间:2022-07-03 21:58:15

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

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

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