0%

状态模式是针对系统的状态转换的,其主要的定义如下:

1
状态模式:允许对象在内部状态改变时改变他的行为,对象看起来好像修改了它的类。

为了方便状态转移 我们为状态定义一个通用的接口,然后每一种状态都实现这个接口,而在系统类中,通过构造函数,将系统本身传入状态类中,这样,每一种状态的改变,都可以在自己类的内部完成,同时提高了可扩展性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public interface State{
public void des();
public void action();
}
public class State1 implements State{
Sys sys;
public Sate1(Sys s)
{
this.sys=sys;
}
public void des(){
.../ implements
}
public void action(){
.../ change the state
sys.setState(s.getState2());
}
}
public class State2 implements State{
Sys sys;
public Sate2(Sys s)
{
this.sys=sys;
}
public void des(){
.../ implements
}
public void action(){
.../ change the state
sys.setState(s.getState1());
}
}
public class Sys {
private State1 state1;
private State2 state2;
private State state;//record the system's state
....//state1 & state2's setter & getter
public Sys(State state)
{
this.state=state;
}
public void setState(State state)
{
this.state=state;
}
public void aciton()
{
state.action();
}
}

虽然在实现上 状态模式和策略模式以及模板方法有些相似 但是几个设计模式完全不一样,策略模式是将可以互换的行为封装起来,然后使用委托的方法决定使用哪一个行为,模板方法则是由子类决定具体的如何实现算法中的某些步骤,而算法的流程是给定的,而状态模式则封装的是基于状态的行为,并将行为委托到当前状态,由当前状态来决定具体行为。

1.迭代器模式完成的功能是和迭代器一样的,封装了对对象的顺序遍历,因为子类的对象集合的存储方式可能并不一致。但是存储的对象是一致的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public classItem{
.....//各种属性
}
public class Set1{
item[] items;
...
public Iterator createIterator(){
return new ItemIterator(items);
}
}
public class Set2{
ArrayList items;
...
public Iterator createIterator(){
return items.iterator();
}
}
public class ItemIterator implements Iterator{
Item[] items;
int position;
public ItemIterator(Item[] items)
{
this.items=items;
position=0;
}
public Object next()
{
Item i=items[position];
position=position+1;
return i;
}
public boolean hasNext()
{
if (position>=items.lenght || items[position]==null)
return false;
else
return true;
}
}

通过这种方法,我们就可以通过自己定义的一个迭代器来访问数组,同时通过createIterator的方法来顺序遍历存储结构不一样的Set1和Set2中item对象。所以迭代器模式就是:

1
迭代器模式:提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露其内部的表示。

2.组合模式

组合模式其实就是整体与部分的一个关系,其实就是一个树形结构,根节点由他的子节点组合而成,而子节点又有自己的子节点来组合而成,所以组合模式的定义如下:

1
组合模式:允许你将对象组合成树形结构来表现“整体/部分”的层次结构,组合能让客户以一致的方法处理个别对象以及对象组合。

现在我们需要对组合模式下的对象这棵进行遍历怎么办?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public abstract class ItemComponent{
....//方法
public void method1(){
}
}
public classItem extends ItemComponent{
.....//各种属性
public void method1()
{
System.out.println("leaf");
}
}
public class Set1 extends ItemComponent{
item[] items;
...
public Iterator Iterator(){
return new ItemIterator(items);
}
public void method1()
{
System.out.println("not leaf");
Iterator iterator=itemComponent.iterator();//重写
while (iterator.hasNext())
{
ItemComponent t=(ItemComponent) iterator.next();
t.method1();
}
}
}
public class Set2 extends ItemComponent{
ArrayList items;
...
public Iterator Iterator(){
return items.iterator();
}
public void method1()
{
System.out.println("not leaf");
Iterator iterator=itemComponent.iterator();//重写
while (iterator.hasNext())
{
ItemComponent t=(ItemComponent) iterator.next();
t.method1();
}
}

}

上面这种方式是一种通过递归的方式来实现全部遍历的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ItemIterator implements Iterator{
stack stack = new Stack();
public ItemIterator(Iterator iter)
{
stack.push(iter);
}

public Object next()
{
if (hasNext()){
Iterator iterator=(Iterator)stack.peek();
ItemComponent t=(ItemComponent) iterator.next();
if (t instanceof Set1)
{
stack.push(t.createIterator());
}
return t;
}else{
return null;
}
}
public boolean hasNext()
{
if (stack.empty()){
return false;
}else{
Iterator iterator=(Iterator) stack.peek();
if (!iterator.hasNext()){
stack.pop();
return hasNext();
}else {
return true;
}
}
}
}

现在定义的这种方式,是通过迭代器用栈模拟递归的一种方式。

3。设计模式-职责单一

1
单一责任: 一个类应该只有一个引起变化的原因。

前面学习过了策略模式,策略模式是对一类的算法进行封装,利用组合,算法之间可以互相替换,但是这个是针对算法过程不是一样的算法。但是如果一系列的算法的步骤都是一样的,且算法的很多过程都是一样的处理,那么,用策略模式的话,会导致算法的重用不高,我们采用模板方法来实现:

1
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class CAL{
public final void algorithm()
{
A1();
A2();
if (Judge())
A3();
A4();
}
public void A1(){
//实现
.....
}
public void A2(){
//实现
.....
}
public abstract void A3(){}
public abstract void A4(){}
public boolean Judge(){
return true;
}
}

其中模板类是一个抽象类,其中算法是确定了的,A1,A2是公共的方法,所有的子类都是一样的,A3,A4是子类自己实现的不一样的函数,定义为抽象方法,子类实现,而Judge方法被成为钩子,默认返回true,而子类可以重写这个方法,这样就能让子类拥有自己的方法。但是这个也反应了模板方法的一个缺点,就是与策略模式相比,弹性不足。

设计模式-好莱坞模式

1
好莱坞模式:别调用我们,我们会调用你。

允许低层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。

1.适配器模式

适配器模式是针对接口不一时处理的情况,比如我的类的参数是IInterface1,但是我现在想要调用IInterface2接口的函数,怎么办呢?就是用适配器来解决这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface IInterface1(){
public void method1();
}
public interface IInterface2(){
public void method2();
}
public class adapter implements IInterface1{
IInterface2 v;
public adapter(IInterface2 t){
this.v=t;
}
public void method1(){
v.method2();
}
}

现在我们调用IIterface2的method1的方法的时候,就是可以直接构造一个适配器来完成

1
2
3
4
5
6
7
8
9
10
11
12
public class A{

public void method3(IInterface1 t)
{
t.method1();
}

public static void main(String[] arg)
{
(new A()).method3(new adapter(claimplementInterfce2));
}
}

其中claimplementInterface2是实现Interface2的一个类的实例。这种适配器的方法被称作为对象适配器,还有一种适配器,叫做类适配器,是基于类的多继承的,其中适配器继承自要适配的两个类,用其中一个类的方法调用另一个类,思想是一致的,不过java不支持多继承,所以也就是只能用对象适配器。

1
适配器模式:将一个类的接口,转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间

2.外观模式

外观模式,其实就是对一个子系统的方法进行整理,对外公开一些方法,方便外部的调用,但是并不是对这些类的一个封装,只是提供了一个简单的接口,用户如果觉得没什么用出,可以直接调用子系统的方法,而且,一个子系统可以有很多个外观。所以外观模式的定义如下

1
外观模式:提供一个统一的接口,用来访问子系统的一群接口。外观定义了一个高层接口,让子系统更容易使用。

比如我们用电脑,怎么开机,怎么关机呢:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class UseComputer{
ZHUJI zhuji;
XIANSHIQI xianshiqi;
...
public UseComputer(ZHUJI zhuji,XIANSHIQI xianshiqi,....)
{
this.zhuji=zhuji;
this.xianshiqi=xianshiqi;
.....
}
public void guanji()
{
zhuji.off();
xianshiqi.off();
}
public void kaiji()
{
xianshiqi.on();
zhuji.on();
}
}

这样就直接提供给用户开机和关机的操作了,而不用用户自己去调用开机关机的一系列的方法了。

3.设计原则

1
最少知识原则:只和你的密友谈话

需要做到这个原则,建议只调用一下的范围的方法:

1
2
3
4
对象本身
被当作方法的参数而传递进来的对象
此方法所创建或实例化的任何对象
对象的任何组组件

命令模式这个设计模式更像是对接口编程的一种应用,比如给小朋友穿衣服,但是不一样的衣服有不一样的穿法,裤子,衬衫,鞋,T恤都是不一样的,但是小朋友不知道怎么穿,只知道想穿什么,那么怎么办呢,小朋友会让他的妈妈帮他穿,这里面的“让妈妈帮忙”,就是给妈妈一个命令(虽然不是很恰当- -!),对小朋友而言,怎么穿他并不关心,反正只要有只要让妈妈穿就行了,所以我们只要定义一个穿的接口就行

1
2
3
4
public interface Wear()
{
public void excute();
}

然后继承这个穿,有很多种执行方式,比如穿鞋,穿衬衫,穿裤子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class WearShoe implements Wear{
public void excute()
{
.....//穿鞋的动作
}
}
public class WearShirt implements Wear{
public void excute()
{
.....//穿衬衫的动作
}
}
public class WearPants implements Wear{
public void excute()
{
.....//穿裤子的动作
}
}

对于妈妈来说,只要知道小朋友要穿什么,帮他穿上就好了:

1
2
3
4
5
6
7
8
9
10
11
public class Mom{
Wear wear;
public setCommand(Wear wear)
{
this.wear = wear;
}
public void Do()
{
wear.excute();
}
}

小朋友要做的事就是告诉妈妈我想穿什么,让妈妈帮它穿好就行了,具体怎么穿,他才不管呢

1
2
3
4
5
6
7
8
9
10
11
12
public class Child{
public static void main()
{
Mom mom=new Mom();
WearShoe wearShoe=new WearShoe();
WearPants wearPants=new WearPants();
mom.setCommand(wearShoe);
mom.excute();
mom.setCommand(wearPants);
mom.excute();
}
}

所以可以看出命令模式其实就是:

1
命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象,命令模式也支持可撤销的操作

其中可撤销的操作其实就是在接口中加入脱衣服的接口,这样子既可以帮小朋友穿衣服也可以帮他脱掉衣服:

1
2
3
public interface Wear()
{
public void excute();
1
2
    public void undo();
}

然后再实现接口的对象中实现它就可以了。

命令模式在多线程处理任务的时候非常有效,只要将命令封装的对象,放入任务队列中,不同的线程通过队列获取对象,直接执行对象的excute()方法就行,而不用管具体命令是怎么执行的。

工程中,某些对象我们只需要一个,比如线程池,缓存,对话框等的对象,我们通常的做法是可以定一个全局静态变量,然后通过程序初始化的时候就实例化他们,然后直接调用这个全局变量,但是这样有个问题,如果我的这个对象消耗的资源很多,而有的时候,我的程序在运行过程中又没用到这个对象,岂不是浪费了很多资源。通常的做法就是定义全局静态变量的时候,不初始化他,而是在调用过程中实例化,这样的话,对于全局变量的实例化,我们就要判断这个变量是否已经实例化了,如果实例化了的吧,我们就不对它进行实例化,所以代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class A
{
private A(){}
public static A cla;
public static A getInstance()
{
if (cla == null){
cla=new A();
}
return cla;
}
}

这里的A的构造器是私有的,这样子可以有效的保证A这个类不会再外部被实例化,从而保证他的唯一性,我们通过getInstance来获取A的全局唯一变量cla,这样就有效的解决了上面这个问题,但是问题又来了,多线程访问getInstance()的时候?cla完全可能出现实例化一次之后又被实例化,怎么办?

1
2
3
4
5
6
7
8
9
10
11
12
public class A
{
private A(){}
public static A cla;
public static synchronized A getInstance()
{
if (cla == null){
cla=new A();
}
return cla;
}
}

我们就为A获取实力的方法getInstance增加一个同步锁来保证方法只能被唯一访问,可是,同步锁势必会降低运行效率,而且我们发现,事实上,也就是第一次实例化的时候会出现问题需要同步锁,以后再需要获取这个对象的时候完全不需要,如果我们频繁的获取对象的话,效率的影响就会相当大。回到最开始的做法?设置全局变量,程序运行的时候就实例化对象?

1
2
3
4
5
6
7
8
9
public class A
{
private A(){}
public static A cla = new A();
public static synchronized A getInstance()
{
return cla;
}
}

这个确实是种方法,但始终不是最好的方法,我们想到,之前所说的,只有在实例化的时候才需要同步锁,那么我们就想到采用双重检查加锁的方法,只在实例化的时候加锁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class A
{
private A(){}
public volatile static A cla;
public static A getInstance()
{
if (cla == null){
synchronized(A.class){
if (cla==null){
cla=new A();
}
}
}
return cla;
}
}

其中volatile的关键字是确保多线程在cla变量初始化的时候,正确的处理cla变量。(volatile用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A))

在面向对象的编程中,我们常常会用到new这个关键字,同时,面向对象可以实现多态,这样的话,我们常常就会用父类或者接口定义一个变量,在用到这个变量的时候,再new一个具体的对象,但是有的时候,这个new的对象不是确定的,可能是要根据不同的场景,new出不同的子类,这个很简单的就可以通过if 或者switch来判断实现,但是,这样子以来的话,如果在很多个地方都出现了这种情况,岂不是都要在这些个地方来写这些一样的代码?这样真的好么?

工厂模式就是用来解决这种对象的生成的办法。工厂模式主要分为3种:简单工厂,工厂方法,抽象工厂。

简单工厂:

 简单工厂其实就是将对象的生成单独抽象出来成为一个单独的类,这样子就可以在生成对象的时候,直接调用这个类的create的方法来返回一个对象。有的时候,这个生成类的方法可以写成静态的,也就是所说的静态工厂.

  但是有的时候,这个类生成方法,对于不同的类,生成的过程是不一样的,比如A类,只需要1、2、3这3个类,B类只会生成4,5,6这3个类,如果用简单工厂的话,一是会显得很冗余,逻辑处理很烦,二是每多一个if的判定都会降低效率。我们就把对应的工厂方法放到了不同的类中

工厂方法:

  工厂方法就是不把具体的生成类的过程单独抽象成一个类,而是在A,B这两个父类中,定义一个抽象方法createXX(),然后在A,B这两个子类中针对自己实现createXX()方法。

抽象工厂:

抽象工厂可以针对一组对象的生成,比如A类B类都要有一个1 2 3 这3个类,这3个类是3种类别是一个父类,又分别分为几种,1类中有1a,1b,1c,2类3类中一样,我们的A对象需要的是1a,2b,3a,B对象需要的是1b,2a,3c,那么我们就定义个抽象的工厂类,分别分为create1(),create2(),creat3(),3个方法,然后继承过来两个工厂类,分别返回A,B类需要的工厂,我们在A类,B类的构造函数中注入这两个工厂实现类,就可以调用他们的create1,create2,create3的方法来获取自己想要的1,2,3这3种类了。

设计原则:

工厂模式中用到了一个设计原则,依赖倒置原则:

依赖倒置原则:依赖抽象,不要依赖具体类
其实我的感觉就是定义变量的时候定义父类,而不是具体子类,对象的构建就需要动态的生成,要完成依赖倒置,可以依据下面的方法:

变量不可以持有具体类的引用
不要让类派生自具体类
不要覆盖基类中已实现的方法

​ 这一章看完之后,我感觉,装饰者模式就是对类继承的一种递归调用式的组合应用,很好的是实现了开闭原则,可以有效的扩展应用程序。比如书中的例子,有几种饮料,每种饮料的价格已经知道了,但是我们又有很多种的调料,每种调料也有它的价格,我们现在需要是在饮料中加调料,那么这样一来,饮料的售价就会变化,如何来描述这种售价呢?如果通过对调料种类的组合来定义若干的类,肯定是非常愚蠢的行为。

​ 通过装饰者模式,就能很好的解决这个问题,我们将这些类分为装饰类(调料),待装饰类(饮料)两种,这两种类继承同一个父类,不同的是装饰类中的构造函数有一个父类引用的构造函数,这样子就可以递归调用构造函数来进行 装饰了。

1
2
3
4
5
6
7
8
9
10
11
12
public class A extends BaseClass{

public string who()
{
return "A";
}

public int cost()
{
return 5;
}
}

我们定义一个待装饰类A,再定义几个装饰类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class decorator1 extends BaseClass{
BaseClass baseClass;
public decorator1(BaseClass t)
{
this.baseClass = t;
}
public string who()
{
return baseClass.who()+",decoratro1";
}
public int cost()
{
return baseClass.cost()+10;
}
}
public class decorator2 extends BaseClass{
BaseClass baseClass;
public decorator2(BaseClass t)
{
this.baseClass = t;
}
public string who()
{
return baseClass.who()+",decoratro2";
}
public int cost()
{
return baseClass.cost()+20;
}
}

然后我们在用decorator1 和decorator2 来装饰A的时候,就有了很犀利的调用方法:

1
2
3
4
5
A  a;
a=new decorator1(a);
a=new deocorator2(a);
system.out.println(a.who());
system.out.println(a.cost());

这样子 输出就是

1
2
A,decorator1,decorator2
35

实际的调用过程就是一个递归的过程。

装饰者模式的定义:

1
装饰者模式:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更具有弹性的替代方案

其中用到的设计原则:

1
开闭原则:对扩展开放,对修改关闭

在项目设计阶段,处理一对多的依赖关系类的时候,我们需要降低代码的耦合性从而增强可扩展性,比如一个班级,班主任老师和学生的关系,对于学校的通知,必定不会是学生没事的时候就问一下班主任”学校有通知没啊?”(铁定会把班主任搞毛的),明智的做法则是等着班主任在班级里面通知(对于学校的通知,班主任不会不通知学生的),在这个关系里,班主任就是所谓的被观察者,而学生则是观察者,也就是所谓的观察者模式:

观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态的时候,他的所有依赖都会收到通知并自动更新

对于观察者模式中所说的通知,就是在被观察者的状态改变的时候,能够让所有观察者根据这种变化作出反应,对于被观察者,他的手里应该有一张观察者的名单,只有这样,才能在状态改变的时候,给出观察者通知,就如上面的例子,班主任只有知道他们班有哪些学生,才能通知到位,当然有的时候,有的学生并不想知道学校的那些通知,那么他就要从老师那边把自己的名字从通知名单中删除掉,但是如果有一天他又想听了,那么对名单还有提供增加一个观察者的名单,之所以命名为观察者和被观察者,而不是通知者和被通知者,就是因为观察者有是否观察的主动权,按照前面一章所讲的,针对接口编程,我们就可以设计出一个被观察者的接口:

1
2
3
4
5
public interface Observerable{
public void addObserver(Observer o);
public void deleteObserver(Observer o);
public void notifyChanged();
}

对于观察者,他的职责就是等着被观察者的更新,然后更新自己的状态,我们也设计出他的接口

1
2
3
public interface Observer{
public void update(object[] data);
}

很明显的观察者在运行的时候,必须知道知道自己的观察对象是谁,所以在观察者类中应该有个变量记录被观察者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Observer1 implements Observer{

private Observerable subject;

public Observer1(Observerable subject)
{
this.subject=subject;
subject.addObserver(this);
}

public void update(object\[\] data)
{
........
}
}

在java的java.until包中 也提供了这两个接口,但是与我们不同的是,他的被观察者ObserverAble不是一个接口而是一个类,其中提供了setChanged()的这个函数,这个函数的作用就是设定changed的值从而决定是否通知所有的观察者是否更新,因为有些变化并不一定是要通知观察者,比如学校专门给老师发的工资调整的通知,这个真的有必要告诉学生么?(另外需要注意的是,java这个ObserverAble类,提供的setChanged方法是protected的,所以你要是用它,就必须继承这个类,如果你要同时继承另外一个类的话,….) 另一个问题,学生向学校提交了一份申请,但是,老师那边久久没有回应,怎么办,学生一直等下去么?肯定不行的,必定是要主动向老师询问结果的,这也就意味着,我们的观察者可以主动的从被观察者那边获取数据,那么观察者就必须提供对应数据的get方法。 另外这一章中也提到了一个新的设计原则:

为交互对象间的松耦合设计而努力

​ 在实际开发过程中,经常会发生这样的一件事,我们需要实现一系列的功能,这些功能在逻辑上是可以抽象成一样的方法,不同的实现,也就是多态,有一种解决方法是,设计一个基类,然后我们定义一些方法,然后继承这个类,设计不同的子类,不同的实现,这样子我们就可以定义基类来调用子类的方法,实现多态,这种方法一定程度上是实现了代码复用。

​ 但是会有一个问题,假设,基类BaseClass具有一个方法,他们的子类都具有两个方法A和B,其中方法A的实现,所有的子类都一样,很明显A的实现方法是放在基类中实现的,如果B的方法每个子类的实现都不是一样的,那么毫无疑问的是我们会在每个子类中重写B的实现。这些都是显而易见的,但是某一天需求变了,BaseClass的子类childClass1,childClass2的B方法的实现是完全一样的,childClass3,childClass4的B方法的实现也是一样的,如果我们再在每个子类中实现这个方法,很明显,代码复用很不完美。也许我们会这样子解决这个问题:

​ 在现有的基类和子类中再添加一层,分别为childClass1,childClass2添加由BaseClass继承而来的一个父类,使得这两个子类从新增的这个类中继承,而他们的B方法的实现放在这个新增的类中,同样的操作对childClass3,childClass4进行。

​ 这个方法一定程度上是解决了上面的问题,但是新的问题又出现了,如果再来一个方法C,childClass2和childClass3的方法C的实现又是一样的,那又该怎么办?显然我们的设计很有问题。此时我们就需要题目中所说的设计模式—-策略模式。

  策略模式的概念太过抽象,我们先看看如何解决上诉问题:

​ 我们通过接口来解决这些变化的方法,我们针对可能会变化的B,C两个方法分别定义一个接口interfaceB,interfaceC,针对childClass1,childClass2我们定义一个类classB1用他们的方法B来实现interfaceB,同理我们生成classB2,classC1,classC2,classC3分别对应不同的方法B和C的实现,这样子,我们只要在基类中定义一个B,C类型为interfaceB,interfaceC的方法引用变量和两个引用对应的setter方法,就可以在子类的构造函数中通过setter方法定制属于自已的方法B,C了,从而很好的实现了代码复用的同时,降低了耦合性,增强了可扩展性。

 我们将这种方法B和C称为策略,那么我们的策略模式,就是针对每一类方法我们定义一套策略,这一套策略是对一类方法的不同实现,他们之间可以互相替换,这种方法可以让算法的变化独立在了使用算法的客户。

 这一章里面,也抽象出了下面的3种设计原则:

1、封装变化
2、多用组合,少用继承
3、针对接口编程,不针对实现编程