精炼23种设计模式

[toc]

一、创建型


工厂模式

简单工厂模式

以继承的思想分别生产不同的产品。

例:

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 interface CPU(){
void createCPU();
}
public class IntelCPU implements CPU{

@Override
public void createCPU(){
//具体实现
}
}
public class AMDCPU implements CPU{

@Override
public void createCPU(){
//具体实现
}
}
//工厂
public class CPUFactory{
public void createCPU(int cpuType){
CPU cpu = null;
if(cpuType == 1 ){
cpu = new IntelCPU(); //生产IntelCPU,实现细节略。
}else if(cpuType == 2 ){
cpu = new AMDCPU(); //生产AMD CPU ,实现细节略。
}else{
return null;
}
}
}

抽象工厂模式

以继承+归类的思想分别生产不同的产品。

例:

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
public interface Factory{
CPU createCPU();
MainBoard createMainBoard();
}
public class IntelFactory implements Factory{
@Override
public CPU createCPU(){
return new IntelCPU();
}
@Override
public MainBoard createCPU(){
return new IntelMainBoard();
}

}
public class AMDFactory implements Factory{
@Override
public CPU createCPU(){
return new AMDCPU();
}
@Override
public MainBoard createCPU(){
return new AMDMainBoard();
}
}

工厂方法模式

在抽象工厂模式的基础上,更加复杂化子类,让子类再归类,然后再生产不同的产品。

例:将文件导出为指定形式(html和pdf,但是还要配合具体的部门,比如标准的输出、财务的输出等),如何设计?

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public interface ExportFactory{
ExportFile factorty(String type);
}
}
public class ExportHtmlFactory implements Factory{
@Override
public ExportFile factorty(String type){
if("standard".equals(type)){
return new ExportStandardHtmlFile();
}else if("financial".equals(type)){
return new ExportFinancialHtmlFile();
}else{
throw new Exception("未找到");
}
}
}
public class ExportPDFFactory implements Factory{
@Override
public ExportFile factorty(String type){
if("standard".equals(type)){
return new ExportStandardPDFFile();
}else if("financial".equals(type)){
return new ExportFinancialPDFFile();
}else{
throw new Exception("未找到");
}
}
}
public interface ExportFile{
public boolean export(String data);
}
public class ExportStandardHtmlFile implements ExportFile{
@Override
public boolean export(String data){
//业务逻辑
System.out.println("标准的HMTL输出");
return true;
}
}
public class ExportFinancialHtmlFile implements ExportFile{
@Override
public boolean export(String data){
//业务逻辑
System.out.println("财务的HMTL输出");
return true;
}
}
public class ExportStandardPDFFile implements ExportFile{
@Override
public boolean export(String data){
//业务逻辑
System.out.println("标准的PDF输出");
return true;
}
}
public class ExportFinancialPDFFile implements ExportFile{
@Override
public boolean export(String data){
//业务逻辑
System.out.println("财务的PDF输出");
return true;
}
}
//客户端
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String data = "";
ExportFactory exportFactory = new ExportHtmlFactory();
ExportFile ef = exportFactory.factory("financial");
ef.export(data);
}
}

建造者模式

建造模式可以将一个产品的内部表象(internal representation)与产品的生产过程分离,从而可以生成具有不同的内部表象的产品。

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
//产品
public class Product(){
private String part1;
private Strign part2;
//省略set/get
}
//抽象建造者
public interface Builder{
void buildPart1();
void buildPart2();
Product retrieveResult();
}
public class concreteBuilder implements Builder{
private Product product = new Product();
@Override
public void buildPart1(){
//生产第一部分
}
public void buildPart2(){
//生产第二部分
}
public void retrieveResult(){
return product;
}
}
public class Director {
private Builder builder;
public Director(Builder builder){
this.builder = builder;
}
public void construct(){
this.builder.buildPart1();
this.builder.buildPart2();
}
}
//客户端
public class Client {
public static void main(String[]args){
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.retrieveResult();
System.out.println(product.getPart1());
System.out.println(product.getPart2());
}
}

原型模式

给出一个原型对象来指明所创建的对象的类型,然后复制这个原型对象创建出更多同类型的对象。

|- 克隆:克隆的对象和原对象不是同一个对象,但是类型与原对象类型相同。

    |- 浅克隆: 所有的对其他对象的引用都仍然指向原来的对象,Object类的clone()方法默认是浅克隆。

     |- 深度克隆:除了浅度克隆所要克隆的东西外,还要复制原对象所引用的对象。通常让对象实现Serializable接口,然后写入流(序列化),然后读出来(反序列化)。

例:

1
2
3
4
5
6
7
8
9
10
public Object deepClone() throws Exception{
//序列化,将对象写到流里
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化,从流里读出来
ByteArrayInputStream bis = new ByteArrayInputStream();
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}

例:

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
//抽象原型角色
public interface Prototype{
//克隆自身的方法
public Object clone();
}
//具体原型角色
public class ConcretePrototype1 implements Prototype{
public Prototype clone(){
Prototype prototype = new ConcretePrototype1();
return prototype;
}
}
public class ConcretePrototype2 implements Prototype{
public Prototype clone(){
Prototype prototype = new ConcretePrototype2();
return prototype;
}
}
//客户端
public class Client {
private Prototype prototype;
pulic Client(Prototype prototype){
this.prototype = prototype;
}
public void operation(Prototype example){
Prototype copy = prototype.clone();
}
}

单例模式

确保某一个类只有一个实例,单例类需要想全局提供该类的实例。

|- 创建一个静态的私有单例类的实例。

|- 构造方法私有化,避免外界直接new该单例类。

|- 提供一个供外界访问的静态方法。

懒汉模式

需要的时候再new对象。

1
2
3
4
5
6
7
private static Singleton instance = null;
public static synchronized Singleton getInstance(){
if(object == null){
instance = new xxx();
}
return instance;
}

饿汉模式

先new对象,等到需要再使用。

1
2
3
4
private static Singleton instance =new xxx();
public static Singleton getInstance(){
return instance;
}

双重检查加锁

|- 第一重检查:不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后先检查实例是否存在,如果不存在再进入下面的同步块。

|- 第二重检查:进入同步块后,再次检查实例是否存在,如果不存在,就在同步情况下创建一个实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private volatile static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
//先检查实例是否存在
if(instance == null){
//同步块,线程安全的创建实例
synchronized(Singleton.class){
//再次检查实例是否存在
if(instance == null){
instance = new Singleton();
}
}
}
}

Lazy initialization holder class模式

综合使用了Java的类级内部类和多线程缺省同步锁的知识,很巧妙地同时实现了延迟加载和线程安全。

|- 类级内部类:由static 修饰的内部类。

|- 多线程缺省同步锁的知识:在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是在某些情况中,JVM已经隐含地为您执行了同步,这些情况下就不用自己再来进行同步控制了。如:

      |- 静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时

      |- 访问final字段时

      |- 在创建线程之前创建对象时

      |- 线程可以看见它将要处理的对象时

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {
private Singleton(){}
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
*/
private static class SingletonHolder{
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
}

public static Singleton getInstance(){
return SingletonHolder.instance;
}
}

|- 枚举实现单例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public enum Singleton {
/**
* 定义一个枚举的元素,它就代表了Singleton的一个实例。
*/

uniqueInstance;

/**
* 单例可以有自己的操作
*/
public void singletonOperation(){
//功能处理
}
}

二、结构型

适配器模式

把一个接口转换成另一种接口从而能够匹配成客户端需要的接口。

类适配器模式

把适配类的API转换成目标类的API。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface Target{
public void method1();
public void method2();
}
public class Adaptee{
public void method2();
}
public class Adapter extends Adaptee implements Target{
@Override
public void method1(){
//实际代码
}
}

对象适配器模式

对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
//如上的Target和Adaptee
public class Adapter{
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
public void method1(){
//实际代码
}
public void method2(){
this.adaptee.method2();
}
}

装饰者模式

Wrapper模式,以对客户端透明的方式扩展对象的功能,是继承关系的一种替代。

|- 装饰模式的用意是在不改变接口的前提下,增强所考虑的类的性能。

|- 允许装饰模式改变接口,增加新的方法。

透明装饰模式

透明的装饰模式也就是理想的装饰模式,要求具体构件角色、装饰角色的接口与抽象构件角色的接口完全一致。

半透明装饰模式

装饰角色的接口与抽象构件角色接口不一致。

例:Java中的I/O设计模式,就是典型的装饰模式。
|- InputStream

    |- ByteArrayInputStream

     |- FileInputStream

     |- FilterInputStream

     |- BufferedInputStream

     |- DataInputStream

     |- LineNumberInputStream

     |- PushbackInputStream
//典型的半透明装饰模式,因为它扩展了一个unread()方法,这个方法是抽象接口所没有的。

     |- ObjectInputStream

     |- PipedInputStream

     |- SquenceInputStream

     |- StringBufferInputStream

适配器模式(做对比)

半透明装饰模式是介于透明装饰模式和适配器模式之间的一种设计模式。
例:

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
//抽象构件角色
public interface Component{
public void sampleOperation();
}
//具体构件角色
public class concreteComponent implements Component{
@Override
public void sampleOperation(){
//具体业务
}
}
//装饰角色
public class Decorator implements Component{
private Component component;

public Decorator(Component component){
this.component = component;
}
@Override
public void sampleOperation(){
//委派给构件
component.sampleOperation();
}
}
//具体装饰角色
public class ConcreteDecoratorA extends Decorator{
public ConcreteDecoratorA(Component component){
super(component);
}
@Override
public void sampleOperation(){
super.sampleOperation();
//相关业务代码
}
}
public class ConcreteDecoratorB extends Decorator{
public ConcreteDecoratorB(Component component){
super(component);
}
@Override
public void sampleOperation(){
super.sampleOperation();
//相关业务代码
}
}

桥接模式

将抽象部分与它的实现部分分离,使他们都可以独立变化,目的是提高系统的可扩展性。

情景:将n种颜色涂在n种形状里,如何设计?

|- 提供两个父类一个是颜色、一个形状,颜色父类和形状父类两个类都包含了相应的子类,然后根据需要对颜色和形状进行组合。

例:

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
public abstract class Shape {
Color color;
public void setColor(Color color){
this.color = color;
}
public abstract void draw();
}
public interface Color {
void bepaint(String shape);
}
public class black implements Color {
@Override
public void bepaint(String shape) {
System.out.println("黑色 -->" + shape);
}
}
public class White implements Color {
@Override
public void bepaint(String shape) {
System.out.println("白色 -->" + shape);
}
}
public class Circle extends Shape{
@Override
public void draw() {
color.bepaint("圆形");
}
}
public class Rectangle extends Shape{
@Override
public void draw() {
color.bepaint("长方形");
}
}
//客户端
public class Client {
public static void main(String[] args) {
Color white = new White();
Shape rectangle = new Rectangle();
rectangle.setColor(white);
rectangle.draw();
}
}

结果:

白色 –>长方形

组合模式

以树的结构来描述部分与整体的概念,和文件系统类似,父文件夹、文件、子文件、子文件夹等等。

安全式

要求管理聚集的地方只出现树枝构件中,而不出现在树叶构件中。

例:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//抽象构件角色
public interface Component{
//输出组件自身的名称
public void printStruct(String preStr);
}
//树枝构件
public class Composite implements Component{
//存储包含的子组件
private List<Component> childComponents = new ArrayList<>();
//组合对象的名字
private String name;
public Composite(String name){
this.name = name;
}
//增加一个子构件
public void addChild(Component child){
childComponents.add(child);
}
//删除一个子构件
public void removeChild(int index){
childComponents.remove(index);
}
public List<Component> getChilds(){
return childComponents;
}
//打印
@Override
public void printStruct(String preStr){
System.out.println(preStr + "+" + this.name);
if(this.childComponents!=null){
preStr = " ";
for(Component c : childComponents){
c.printStruct(preStr);
}
}
}
}
//树叶构件
public class Leaf implements Component{
private String name;
public Leaf(String name){
this.name = name;
}
@Override
public void printStruct(String preStr){
System.out.println(preStr + "-" + name);
}
}
//客户端
public class Client{
public static void main(String[] args){
Composite root = new Composite("服装");
Composite c1 = new Composite("男装");
Composite c2 = new Composite("女装");

Leaf leaf1 = new Leaf("衬衫");
Leaf leaf2 = new Leaf("夹克");
Leaf leaf3 = new Leaf("裙子");
Leaf leaf4 = new Leaf("套装");

root.addChild(c1);
root.addChild(c2);
c1.addChild(leaf1);
c1.addChild(leaf2);
c2.addChild(leaf3);
c2.addChild(leaf4);

root.printStruct("");
}
}

透明式

透明式的合成模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口。

例:

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 abstract class Component {
/**
* 输出组建自身的名称
*/
public abstract void printStruct(String preStr);
/**
* 聚集管理方法,增加一个子构件对象
* @param child 子构件对象
*/
public void addChild(Component child){
/**
* 缺省实现,抛出异常,因为叶子对象没有此功能
* 或者子组件没有实现这个功能
*/
throw new UnsupportedOperationException("对象不支持此功能");
}
/**
* 聚集管理方法,删除一个子构件对象
* @param index 子构件对象的下标
*/
public void removeChild(int index){
/**
* 缺省实现,抛出异常,因为叶子对象没有此功能
* 或者子组件没有实现这个功能
*/
throw new UnsupportedOperationException("对象不支持此功能");
}

/**
* 聚集管理方法,返回所有子构件对象
*/
public List<Component> getChild(){
/**
* 缺省实现,抛出异常,因为叶子对象没有此功能
* 或者子组件没有实现这个功能
*/
throw new UnsupportedOperationException("对象不支持此功能");
}
}

Composite和Leaf与上面一样,不一样的是Client端,Client不需要关心他们之间的关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Client {
public static void main(String[] args) {
Component root = new Composite("服装");
Component c1 = new Composite("男装");
Component c2 = new Composite("女装");

Component l1 = new Leaf("衬衫");
Component l2 = new Leaf("长袖");
Component l3 = new Leaf("毛衣");
Component l4 = new Leaf("貂皮");
root.addChild(c1);
root.addChild(c2);
root.addChild(l1);
root.addChild(l2);
root.addChild(l3);
root.addChild(l4);
root.printStruct("");
}
}

外观模式(Facade)

外观模式主要是将客户端直接与多个模块打交道的方式改为客户端与门面打交道,然后门面再去与各个模块打交道。客户可以不知道各个模块的具体实现甚至可以不用知道模块是否存在。

例:

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
public class ModualA{
public void test();
}
public class ModualB{
public void test();
}
public class ModualC{
public void test();
}
public class Facade{
public void test(){
ModualA a = new ModualA();
a.test();
ModualB b = new ModualB();
b.test();
ModualC c = new ModualC();
c.test();
}
}
public class Client{
public static void main(String[] args){
Facade facade = new Facade();
facade.test();
}
}

|- Facade模式还可以用在子系统的某些功能不需要暴露给其他子系统的情况,如下:

例:

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 ModualA{
//暴露给其他子系统的方法
public void test1(){

}
//不暴露给其他子系统的方法
private void test2(){

}
}
public class ModualB{
//暴露给其他子系统的方法
public void test1(){

}
//不暴露给其他子系统的方法
private void test2(){

}
}
public class Facade{
ModualA a = new ModualA();
ModualB b = new ModualB();
public void testa(){
a.test1();
}
public vid testb(){
b.test2();
}
}

享元模式

以共享的方式高效地支持大量的细粒度对象,目的是减少多次利用的对象重复创建对内存造成较大的开销。

|- 英文是flyweight,轻量级的。但是根据设计模式中的概念,将此译为享元,意思是共享元数据,相当于共享对象。

|- Java中String类型就是使用了享元模式,String对象是final类型的,Java中的字符串常量都是存在常量池中的。

例:

1
2
3
String a = "abc";
String b = "abc";
System.out.println(a==b);

结果为:true

单纯享元模式:共享对象

共享对象

例:

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
public interface FlyWeight{
//具体业务类,这里简写一个
public void operation(Character state);
}
public class ConcreteFlyWeight implements FlyWeight {
private Character intrinsicState = null;
public ConcreteFlyWeight (Character state){
this.intrinsicState = state;
}
public void operation(Character state){
System.out.println("intrinsicState :" + this.intrinsicState);
System.out.println("extrinsicState :" + state);
}
}
public class FlyWeightFactory{
private Map<Character,FlyWeight> files = new HashMap<>();
public FlyWeight factory(Character state){
FlyWeight fly = files.get(state);
//判断是否已经有了这个对象
if(fly ==null){
//如果没有,就创建,并且加入到集合中。
fly = new ConcreteFlyWeight(state);
files.put(state,fly);
}
//如果有,直接返回
return fly;
}
}
public class Client{
public static void main(String[] args) {
FlyWeightFactory factory = new FlyWeightFactory();
FlyWeight fly = factory.factory(new Character('a'));
System.out.println(fly.hashCode());
fly.operation("first");
fly = factory.factory(new Character('b'));
System.out.println(fly.hashCode());
fly.operation("second");
fly = factory.factory(new Character('a'));
System.out.println(fly.hashCode());
fly.operation("third");
}
}

结果如下:

21685669

instrinsicState :a

extrinsicState :first

19997786

instrinsicState :b

extrinsicState :second

21685669

instrinsicState :a

extrinsicState :third

由此可见,第一次和第三次对象的hashCode一样,说明在内存地址中是同一个对象。

复杂享元模式

    将一些单纯享元使用合成模式加以复合,形成复合享元对象。这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。

例:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public interface FlyWeight {
void operation(String state);
}
public class ConcreteFlyWeight implements FlyWeight {
private Character intrinsicState = null;
public ConcreteFlyWeight(Character state) {
this.intrinsicState = state;
}
@Override
public void operation(String state) {
System.out.println("instrinsicState :"+ this.intrinsicState);
System.out.println("extrinsicState :"+ state);
}
}
public class CompositeConcreteFlyWeight implements FlyWeight {
private Map<Character,FlyWeight> files = new HashMap<>();
public void add(Character key,FlyWeight fly){
files.put(key, fly);
}
@Override
public void operation(String state) {
FlyWeight fly = null;
for(Object o : files.keySet()){
fly = files.get(o);
System.out.println(o+": "+fly.hashCode());
fly.operation(state);
}
}
}
public class FlyWeightFactory {
private Map<Character,FlyWeight> files = new HashMap<>();
//复合享元工厂方法
public FlyWeight factory(List<Character> compositeStateList){
CompositeConcreteFlyWeight compoisteFlyWeight = new CompositeConcreteFlyWeight();
for(Character state : compositeStateList){
compoisteFlyWeight.add(state,this.factory(state));
}
return compoisteFlyWeight;
}

public FlyWeight factory(Character state) {
FlyWeight fly = null;
fly = files.get(state);
if(fly == null){
fly = new ConcreteFlyWeight(state);
files.put(state,fly);
}
return fly;
}
}
public class Client {
public static void main(String[] args) {
List<Character> compositeState = new ArrayList<>();
compositeState.add('a');
compositeState.add('b');
compositeState.add('c');
compositeState.add('a');
compositeState.add('b');
FlyWeightFactory flyWeightFactory = new FlyWeightFactory();
FlyWeight compositeFly1 = flyWeightFactory.factory(compositeState);
FlyWeight compositeFly2 = flyWeightFactory.factory(compositeState);
compositeFly1.operation("composite -->");
System.out.println("+++++++++++++++");
System.out.println("复合享元是不可以共享:"+(compositeFly1 == compositeFly2));
System.out.println(compositeFly1.hashCode()+","+compositeFly2.hashCode());
Character state = 'a';
Character state2 = 'b';
FlyWeight fly1 = flyWeightFactory.factory(state);
FlyWeight fly2 = flyWeightFactory.factory(state);
FlyWeight fly3 = flyWeightFactory.factory(state2);
System.out.println("单纯享元是可以共享的:"+(fly1 == fly2));
System.out.println("fly1: " + fly1.hashCode()+",state: "+state);
System.out.println("fly2: " + fly2.hashCode()+",state: "+state);
System.out.println("fly3: " + fly3.hashCode()+",state: "+state2);
}
}

运行结果:

a: 21685669

instrinsicState :a

extrinsicState :composite –>

b: 19997786

instrinsicState :b

extrinsicState :composite –>

c: 24079912

instrinsicState :c

extrinsicState :composite –>

+++++++++++++++

复合享元是不可以共享:false

23050916,32379559

单纯享元是可以共享的:true

fly1: 21685669,state: a

fly2: 21685669,state: a

fly3: 19997786,state: b

代理模式

给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,类似于中介,客户与客户之间无法直接进行交流,需要使用一个媒介。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class AbstractObject {
public abstract void operation();
}
public class RealObject extends AbstractObject {
@Override
public void operation() {
System.out.println("一些操作");
}
}
public class ProxyObject extends AbstractObject {
RealObject realObject = new RealObject();
@Override
public void operation() {
System.out.println("before do ----");
realObject.operation();
System.out.println("after do ----");
}
}

三、 行为型

责任链模式

请求以链式传递,具体哪个类处理客户端不知。Tomcat的Filter处理过程便是责任链模式。

|- 抽象处理者:定义接口,并且持有下一个处理类的对象。

|- 具体处理者:可以根据条件判断是否处理或者移交给下一个处理类处理。

例:

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
//抽象处理角色
public abstract class Handler {
//持有的后继责任对象
protected Handler successor;
//处理请求的方法
public abstract void handlerRequest();
public Handler getSuccessor() {
return successor;
}

public void setSuccessor(Handler successor) {
this.successor = successor;
}
}
//具体处理角色
public class ConcreteHandler extends Handler {
@Override
public void handlerRequest() {
if (getSuccessor() != null) {
System.out.println("放过请求");
getSuccessor().handlerRequest();
}else{
System.out.println("处理请求");
}
}
}
//客户端
public class Client {
public static void main(String[] args) {
//组装责任链
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
//提交请求
handler1.handlerRequest();
}
}

命令模式

把发出命令的责任和执行命令的责任分离,委派给不同的对象。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。

例:

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
//接收者
public class Receiver {
public void action(){
//真正执行命令的操作
System.out.println("执行操作");
}
}
//抽象命令接口
public interface Command {
//执行方法
void excute();
}
//具体命令
public class ConcreteCommand implements Command {
//持有相应的接收者对象
private Receiver receiver = null;

public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void excute() {
receiver.action();
}
}
//请求者
public class Invoker {
private Command command= null;

public Invoker(Command command) {
this.command = command;
}
public void action(){
command.excute();
}
}
//客户端
public class Client {
public static void main(String[] args) {
//创建接收者
Receiver receiver = new Receiver();
//创建命令对象,设置它的接收者
Command command = new ConcreteCommand(receiver);
//创建请求者,把命令设置进去
Invoker invoker = new Invoker(command);
//执行方法
invoker.action();
}
}

注:命令模式使得客户端和具体实现命令的接收者对象完全解耦。

解释器模式

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

|- 通俗来讲就是定义一些规则,用你自己的方式来实现这些规则,并且调用此规则来完成一些功能。

例:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
* 表达式接口
*/
public interface Expression {
boolean interpret(String context);
}
public class TerminalExpression implements Expression {
private String data;

public TerminalExpression(String data) {
this.data = data;
}

@Override
public boolean interpret(String context) {
return context.contains(data);
}
}
/**
* 与表达式
*/
public class AndExpression implements Expression {
private Expression expression1 = null;
private Expression expression2 = null;

public AndExpression(Expression expression1, Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}

@Override
public boolean interpret(String context) {
return expression1.interpret(context)&& expression2.interpret(context);
}
}
/**
* 或表达式
*/
public class OrExpression implements Expression {
private Expression expression1 = null;
private Expression expression2 = null;

public OrExpression(Expression expression1,Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}

@Override
public boolean interpret(String context) {
boolean flag1 = expression1.interpret(context);
boolean flag2 = expression2.interpret(context);
return flag1|| flag2;
}
}
//客户端
public class Client {
//规则:Robert 和 John 是男性
public static Expression getMaleExpression(){
Expression robert = new TerminalExpression("Robert");
Expression john = new TerminalExpression("john");
return new OrExpression(robert,john);
}
//规则:Julie 是一个已婚的女性
public static Expression getMarriedWomanExpression(){
Expression julie = new TerminalExpression("Julie");
Expression married = new TerminalExpression("Married");
return new AndExpression(julie, married);
}

public static void main(String[] args) {
Expression isMale = getMaleExpression();
Expression isMarriedWoman = getMarriedWomanExpression();

System.out.println("John is male? " + isMale.interpret("john"));
System.out.println("Julie is a married women? "
+ isMarriedWoman.interpret("Married Julie"));
}
}

以上代码运行结果为:

John is male? true

Julie is a married women? true

中介者模式

为了减少同事类之间的耦合,独立改变他们之间的交互。

|- 同事类:如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。

|- 情景:类A和类B都持有一个数,要保证A中的数字改变的时候B中的数字乘以100,B中的数字改变的时候,A中的数字除以100。

例(传统方式):

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
public abstract AbstractColleague{
protected int number;
public void setNumber(int number){
this.number = number;
}
public int getNumber(){
return number;
}
public abstract void setNumber(int number,AbstractColleague colleague);
}
public class ColleagueA extends AbstractColleague{
@Override
public void setNumber(int number,AbstractColleague colleague){
this.number = number;
colleague.setNumber(number * 100);
}
}
public class ColleagueB extends AbstractColleague{
@Override
public void setNumber(int number,AbstractColleague colleague){
this.number = number;
colleague.setNumber(number / 100);
}
}
public class Client(){
public static void main(String[] args){
AbstractColleague colleagueA = new ColleagueA();
AbstractColleague colleagueB = new ColleagueB();
colleagueA.setNumber(500,colleagueB);
System.out.println("---------设置A影响B---------");
System.out.println("collA的值 :"+colleagueA.getNumber());
System.out.println("collB的值 :"+colleagueB.getNumber());
colleagueB.setNumber(2500600,colleagueA);
System.out.println("---------设置B影响A---------");
System.out.println("collA的值 :"+colleagueA.getNumber());
System.out.println("collB的值 :"+colleagueB.getNumber());
}
}

运行结果:

———设置A影响B———

collA的值 :500

collB的值 :50000

———设置B影响A———

collA的值 :25006

collB的值 :2500600



例(中介者模式:让中介类参与其中,避免A和B的直接交互):

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
* 中介者模式
*/
public abstract class AbstractColleague {
protected int number;

public int getNumber() {
return number;
}

public void setNumber(int number) {
this.number = number;
}
//这里传入的是一个中介类
public abstract void setNumber(int number,AbstractMediator media);
public void test(){
}
}
public class ColleagueA extends AbstractColleague {
@Override
public void setNumber(int number, AbstractMediator mediator) {
this.number = number;
//让中介类来完成功能
mediator.affectB();
}
}
public class ColleagueB extends AbstractColleague {
@Override
public void setNumber(int number, AbstractMediator mediator) {
this.number = number;
mediator.affectA();
}
}
public abstract class AbstractMediator {
//持有两个实际对象的目的是让他们的状态随着改变。
protected AbstractColleague A;
protected AbstractColleague B;
//构造方法通常是一种非常好的做法,可以让类的状态一直保持着传递状态。
public AbstractMediator(AbstractColleague a, AbstractColleague b) {
A = a;
B = b;
}
public abstract void affectB();

public abstract void affectA();
}
public class Mediator extends AbstractMediator {
public Mediator(AbstractColleague colleagueA,AbstractColleague colleagueB) {
super(colleagueA,colleagueB);
}

@Override
public void affectB() {
int number = A.getNumber();
B.setNumber(number * 100);
}

@Override
public void affectA() {
int number = B.getNumber();
A.setNumber(number / 100);
}
}
//Client
public class Client {
public static void main(String[] args) {
AbstractColleague colleagueA = new ColleagueA();
AbstractColleague colleagueB = new ColleagueB();
AbstractMediator mediator = new Mediator(colleagueA,colleagueB);
colleagueA.setNumber(500,mediator);
System.out.println("---------设置A影响B---------");
System.out.println("collA的值 :"+colleagueA.getNumber());
System.out.println("collB的值 :"+colleagueB.getNumber());
colleagueB.setNumber(2500600,mediator);
System.out.println("---------设置B影响A---------");
System.out.println("collA的值 :"+colleagueA.getNumber());
System.out.println("collB的值 :"+colleagueB.getNumber());
}
}

运行结果如下:

———设置A影响B———

collA的值 :500

collB的值 :50000

———设置B影响A———

collA的值 :25006

collB的值 :2500600



注:一般来说,只有对于那种同事类之间是网状结构的关系,才会考虑使用中介者模式。可以将网状结构变为星状结构,使同事类之间的关系变的清晰一些。

  |- 网状结构:类与类之间是多对多的关系,牵一发而动全身。

  |- 星状结构:各类都与中介类单独联系,不与其他的类牵连。

迭代模式(Cursor)

可以顺序地访问一个聚集中的元素而不暴露聚集的内部表象(internal representation)。

|- Java中的集合框架很多都使用的迭代模式的聚集,如Vector、ArrayList、HashSet、HashMap、Hashtable等。

例:

1
2
3
4
5
6
/**
* 抽象聚集角色类
*/
public abstract class Aggregate {
public abstract Iterator createInterator();
}

/**

  • 具体聚集角色类:
  • 实现了抽象聚集角色类所要求的接口,也就是createIterator()方法。此外,还有方法getElement()向外界提供聚集元素,而方法size()向外界提供聚集的大小等。
    */
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class ConcreteAggregate extends Aggregate {
    private Object[] objArray = null;

    public ConcreteAggregate(Object[] objArray) {
    this.objArray = objArray;
    }

    @Override
    public Iterator createInterator() {
    return new ConcreteIterator(this);
    }
    public Object getElement(int index){
    if(index <objArray.length){
    return objArray[index];
    }
    else{
    return null;
    }
    }
    public int size(){
    return objArray.length;
    }
    }

/**

  •  抽象迭代子角色类
    */
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public interface Iterator {
    //move to first
    void first();
    //move to last
    void next();

    boolean isLast();

    Object currentItem();
    }

/**

  • 具体迭代子角色
    */
    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
    public class ConcreteIterator implements Iterator {
    private ConcreteAggregate agg;
    private int index = 0;
    private int size = 0;

    public ConcreteIterator(ConcreteAggregate agg) {
    this.agg = agg;
    this.index = 0;
    this.size = agg.size();
    }

    @Override
    public void first() {
    index = 0;
    }

    @Override
    public void next() {
    if(index < size){
    index ++;
    }
    }

    @Override
    public boolean isLast() {
    return (index >= size);
    }

    @Override
    public Object currentItem() {
    return agg.getElement(index);
    }
    }

//客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Client {
public void operation(){
Object[] objArray = {"a","b","c","d","e","f","g"};
Aggregate agg = new ConcreteAggregate(objArray);
Iterator iter = agg.createInterator();
while (!iter.isLast()){
System.out.println(iter.currentItem());
iter.next();
}
}
public static void main(String[] args) {
Client client = new Client();
client.operation();
}
}

观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

例:
/**

  • 抽象主题角色类:把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。
  • 抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。
    */
    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
    public class Subject {
    /**
    * 用来保存注册的观察者对象
    */
    private List<Observer> list = new ArrayList<Observer>();
    /**
    * 注册观察者对象
    * @param observer 观察者对象
    */
    public void attach(Observer observer){

    list.add(observer);
    System.out.println("Attached an observer");
    }
    /**
    * 删除观察者对象
    * @param observer 观察者对象
    */
    public void detach(Observer observer){

    list.remove(observer);
    }
    /**
    * 通知所有注册的观察者对象
    */
    public void nodifyObservers(String newState){

    for(Observer observer : list){
    observer.update(newState);
    }
    }
    }

/**

  • 具体角色类:将有关状态存入具体观察者对象;
  • 在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。
    */
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class ConcreteSubject extends Subject {
    private String state;

    public String getState() {
    return state;
    }

    public void change(String newState){
    state = newState;
    System.out.println("主题状态为:" + state);
    //状态发生改变,通知各个观察者
    this.nodifyObservers(state);
    }
    }

/**

  • 抽象观察者角色类:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。
    */
    1
    2
    3
    4
    public interface Observer {
    //更新方法
    void update(String state);
    }

/**

  • 具体观察者角色类:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态协调。
  • 如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。
    */
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class ConcreteObserver implements Observer{
    //观察者的状态
    private String observerState;

    @Override
    public void update(String state) {
    /**
    * 更新观察者的状态,使其与目标的状态保持一致
    */
    observerState = state;
    System.out.println("状态为:"+observerState);
    }
    }

//客户端

1
2
3
4
5
6
7
8
9
10
11
12
public class Client {
public static void main(String[] args) {
//创建主题对象
ConcreteSubject subject = new ConcreteSubject();
//创建观察者对象
Observer observer = new ConcreteObserver();
//将观察者对象登记到主题对象上
subject.attach(observer);
//改变主题对象的状态
subject.change("new state");
}
}

运行结果如下:

Attached an observer

主题状态为:new state

状态为:new state

策略模式

针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。

|- 对算法的包装。

|- 简而言之:准备一组算法,并将每一个算法封装起来,使得它们可以互换。

例(思路模板):

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
/**
* 抽象策略类
*/
public interface Strategy {
//策略方法
void strategyInterface();
}
/**
* 环境角色类
*/
public class Context {
//持有一个具体策略的对象
private Strategy strategy;
/**
* 构造函数,传入一个具体策略对象
* @param strategy 具体策略对象
*/
public Context(Strategy strategy){
this.strategy = strategy;
}
/**
* 策略方法
*/
public void contextInterface(){
strategy.strategyInterface();
}
}
/**
* 具体策略类
*/
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyInterface() {
//业务代码
}
}
/**
* 具体策略类
*/
public class ConcreteStrategyB implements Strategy {
@Override
public void strategyInterface() {
//业务代码
}
}

例(具体事例:图书打折问题,初级会员没有折扣,中级会员9折,高级会员8折):

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
51
52
53
54
55
56
57
58
59
60
/**
* 抽象折扣类
*/
public interface MemberStrategy {
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
double calcPrice(double booksPrice);
}
/**
* 初级会员
*/
public class PrimaryMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于初级会员的没有折扣");
return booksPrice;
}
}
/**
* 中级会员9折
*/
public class IntermediateMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("中级会员9折");
return booksPrice * 0.9;
}
}
/**
* 高级会员8折
*/
public class AdvancedMemberStrategy implements MemberStrategy {
@Override
public double calcPrice(double booksPrice) {
System.out.println("高级会员8折");
return booksPrice * 0.8;
}
}
public class Price {
private MemberStrategy strategy;

public Price(MemberStrategy strategy) {
this.strategy = strategy;
}
//计算书价
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}
public class Client {
public static void main(String[] args) {
MemberStrategy memberStrategy = new AdvancedMemberStrategy();
Price price = new Price(memberStrategy);
double quote = price.quote(300);
System.out.println("图书最终价格为:"+quote);
}
}

运行结果如下:

高级会员8折

图书最终价格为:240.0

模板方法模式

准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。

|- 不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。

|- 模板方法在Servlet中的应用:使用过Servlet的人都清楚,除了要在web.xml做相应的配置外,还需继承一个叫HttpServlet的抽象类。

    |- ttpService类提供了一个service()方法,

    |- 这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。

    |- 这些do方法需要由HttpServlet的具体子类提供。

因此这是典型的模板方法模式。

|- 关键:子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法所代表的顶级逻辑。
例:

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 abstract class AbstractTemplate {
/**
* 模板方法
*/
public void templateMethod(){
abstractMethod();
hookMethod();
concreteMethod();
}
//基本方法(由子类实现)
protected abstract void abstractMethod();
//基本方法(空方法)
protected void hookMethod(){}
//基本方法(已经实现)
protected final void concreteMethod(){
//业务相关代码
}
}
public class ConcreteTemplate extends AbstractTemplate {
//基本方法实现
@Override
protected void abstractMethod() {
//业务相关代码
}
//重写父类方法
@Override
protected void hookMethod() {
//业务相关代码
}
}

访问者模式

封装一些施加于某种数据结构元素之上的操作。

|- 分派的概念:根据对象的类型而对方法进行的选择。

静态分派

发生在编译时期,分派根据静态类型信息发生。静态分派对于我们来说并不陌生,方法重载就是静态分派。

例(墨子骑马的故事作为例子,墨子可以骑白马或者黑马):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Mozi {
public void ride(Horse h){
System.out.println("骑马");
}

public void ride(WhiteHorse wh){
System.out.println("骑白马");
}

public void ride(BlackHorse bh){
System.out.println("骑黑马");
}

public static void main(String[] args) {
Horse wh = new WhiteHorse();
Horse bh = new BlackHorse();
Mozi mozi = new Mozi();
mozi.ride(wh);
mozi.ride(bh);
}
}

运行结果如下:

骑马

骑马

注:但是两次对ride()方法的调用传入的是不同的参数,也就是wh和bh。它们虽然具有不同的真实类型,但是它们的静态类型都是一样的,均是Horse类型。

|- 由此可见:重载方法的分派是根据静态类型进行的,这个分派过程在编译时期就完成了。

动态分派

发生在运行时期,动态分派动态地置换掉某个方法。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Horse {
public void eat(){
System.out.println("马吃草");
}
}
public class BlackHorse extends Horse {
@Override
public void eat() {
System.out.println("黑马吃草");
}
}
public class Client {
public static void main(String[] args) {
Horse horse = new BlackHorse();
horse.eat();
}
}

运行结果如下:

黑马吃草

因此,对比可知:问题的核心就是Java编译器在编译时期并不总是知道哪些代码会被执行。

|- 编译器仅仅知道对象的静态类型,而不知道对象的真实类型。

|- 方法的调用则是根据对象的真实类型,而不是静态类型。

这样一来,上面最后一行的eat()方法调用的是BlackHorse类的eat()方法,打印的是“黑马吃草”。

备忘录模式

在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。

|- 简而言之,复制一份对象的内部状态,保存下来以备不时之需。

白箱备忘录模式

备忘录角色对任何对象都提供一个接口(宽接口),备忘录角色的内部所存储的状态就对所有对象公开。

例:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* 发起人角色类
*/
public class Originator {
//持有一个状态标志
private String state;

public Memento createMemento(){
return new Memento(state);
}
public void restoreMemento(Memento memento){
this.state = memento.getState();
}
public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
System.out.println("当前状态:" + state);
}
}
/**
* 备忘录角色类
*/
public class Memento {
private String state;

public Memento(String state) {
this.state = state;
}

public void setState(String state) {
this.state = state;
}

public String getState() {
return state;
}
}
/**
* 负责人角色
*/
public class CareTaker {
private Memento memento;
//获取备忘录
public Memento retrieveMemento(){
return this.memento;
}
//设置备忘录
public void saveMemento(Memento memento){
this.memento = memento;
}
}
//客户端
public class Client {
public static void main(String[] args) {
Originator o = new Originator();
CareTaker care = new CareTaker();
//创建
o.setState("on");
care.saveMemento(o.createMemento());
//修改
o.setState("off");
//恢复
o.restoreMemento(care.retrieveMemento());
System.out.println(o.getState());
}
}

运行结果如下:

当前状态:on

当前状态:off

on

黑箱备忘录模式

备忘录角色对发起人(Originator)角色对象提供一个宽接口,而为其他对象提供一个窄接口。

|- 在JAVA语言中,实现双重接口的办法就是将备忘录角色类设计成发起人角色类的内部成员类。

例:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* 发起人角色类
*/
public class Originator {
private String state;

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
System.out.println("当前状态 -->" + state);
}
public MementoIF createMemento(){
return new Memento(state);
}
public void restoreMemento(MementoIF memento){
this.setState(((Memento)memento).getState());

//以内部类的方式,将备忘录角色只为发起人角色提供功能。
private class Memento implements MementoIF{
private String state;

public Memento(String state) {
this.state = state;
}

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}
}
}
/**
* 标识接口,窄接口
*/
public interface MementoIF {
}
//负责人角色类
public class CareTaker {
private MementoIF memento;
public MementoIF retrieveMemento(){
return memento;
}
public void saveMemento(MementoIF memento){
this.memento = memento;
}
}
//客户端
public class Client {
public static void main(String[] args) {
Originator o = new Originator();
CareTaker careTak
er = new CareTaker();
o.setState("on");
//此时虽然无法直接访问内部类Menmento,但是通过createMemento()方法可以得到。
careTaker.saveMemento(o.createMemento());
o.setState("off");
o.restoreMemento(careTaker.retrieveMemento());
}
}

运行结果如下:

当前状态 –>on

当前状态 –>off

当前状态 –>on

多重检查点

往往系统中部只需要恢复对象的某一个状态,而是要恢复多个状态。

例:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
public class Originator {
private List<String> states;
//检查点指数
private int index;
/**
* 构造函数
*/
public Originator(){
states = new ArrayList<String>();
index = 0;
}
/**
* 工厂方法,返还一个新的备忘录对象
*/
public Memento createMemento(){
return new Memento(states , index);
}
/**
* 将发起人恢复到备忘录对象记录的状态上
*/
public void restoreMemento(Memento memento){
states = memento.getStates();
index = memento.getIndex();
}
/**
* 状态的赋值方法
*/
public void setState(String state){
states.add(state);
index++;
}
/**
* 辅助方法,打印所有状态
*/
public void printStates(){

for(String state : states){
System.out.println(state);
}
}
}
public class Memento {
private List<String> states;
private int index;
/**
* 构造函数
*/
public Memento(List<String> states , int index){
this.states = new ArrayList<String>(states);
this.index = index;
}
public List<String> getStates() {
return states;
}
public int getIndex() {
return index;
}
}
public class CareTaker {
private Originator o;
private List<Memento> mementos = new ArrayList<Memento>();
private int current;
/**
* 构造函数
*/
public CareTaker(Originator o){
this.o = o;
current = 0;
}
/**
* 创建一个新的检查点
*/
public int createMemento(){
Memento memento = o.createMemento();
mementos.add(memento);
return current++;
}
/**
* 将发起人恢复到某个检查点
*/
public void restoreMemento(int index){
Memento memento = mementos.get(index);
o.restoreMemento(memento);
}
/**
* 将某个检查点删除
*/
public void removeMemento(int index){
mementos.remove(index);
}
}
public class Client {
public static void main(String[] args) {

Originator o = new Originator();
CareTaker c = new CareTaker(o);
//改变状态
o.setState("state 0");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 1");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 2");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 3");
//建立一个检查点
c.createMemento();
//打印出所有检查点
o.printStates();
System.out.println("-----------------恢复检查点-----------------");
//恢复到第二个检查点
c.restoreMemento(2);
//打印出所有检查点
o.printStates();
}

}

运行结果如下:

state 0


state 1

state 2

state 3

—————–恢复检查点—————–

state 0

state 1

state 2

状态模式

允许一个对象在其内部状态改变的时候改变其行为,这个对象看上去就像是改变了它的类一样。

|- 把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。

例(思路模型):

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
//上下文对象
public class Context {
private State state;

public void setState(State state) {
this.state = state;
}
//用户感兴趣的接口方法
public void request(String sampleParam){
state.handle(sampleParam);
}
}
/**
* 抽象状态类
*/
public interface State {
//状态对应的处理
void handle(String sampleParam);
}

public class ConcreteStateA implements State {
@Override
public void handle(String sampleParam) {
System.out.println("ConcreteStateA handle :"+sampleParam);
}
}
public class ConcreteStateB implements State {
@Override
public void handle(String sampleParam) {
System.out.println("ConcreteStateB handle :"+sampleParam);
}
}
//客户端
public class Client {
public static void main(String[] args) {
//创建状态
State stateA = new ConcreteStateA();
State stateB = new ConcreteStateB();
//创建环境
Context context = new Context();
//将状态设置到环境中
context.setState(stateA);
//请求
context.request("test");
context.setState(stateB);
//请求
context.request("test");
}
}

运行结果如下:

ConcreteStateA handle :test

ConcreteStateB handle :test



例(具体事例:投票事件,分为普通投票、重复投票、恶意刷票、黑名单禁止刷票几种状态):

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public interface VoteState {
/**
*
* @param user 投票人
* @param voteItem 投票项目
* @param voteManager 投票上下文,用来传递上下文状态。
*/
void vote(String user,String voteItem,VoteManager voteManager);
}
public class NormalVote implements VoteState {
@Override
public void vote(String user, String voteItem, VoteManager voteManager) {
//正常投票,记录到投票记录中
voteManager.getMapVote().put(user, voteItem);
System.out.println("恭喜投票成功");
}
}
public class RepeatVoteState implements VoteState {
@Override
public void vote(String user, String voteItem, VoteManager voteManager) {
//重复投票,暂时不做处理
System.out.println("请不要重复投票");
}
}
public class SpiteVoteState implements VoteState {
@Override
public void vote(String user, String voteItem, VoteManager voteManager) {
// 恶意投票,取消用户的投票资格,并取消投票记录
String str = voteManager.getMapVote().get(user);
if(str != null){
voteManager.getMapVote().remove(user);
}
System.out.println("你有恶意刷屏行为,取消投票资格");
}
}
public class BlackVoteState implements VoteState {
@Override
public void vote(String user, String voteItem, VoteManager voteManager) {
//记录黑名单中,禁止登录系统
System.out.println("进入黑名单,将禁止登录和使用本系统");
}
}
public class VoteManager {
//持有状态处理对象
private VoteState state = null;
//记录用户投票的结果
private Map<String,String> mapVote = new HashMap<>();
//记录用户投票次数
private Map<String,Integer> mapVoteCount = new HashMap<>();
//获取用户投票结果
public Map<String,String> getMapVote(){
return mapVote;
}
public void vote(String user,String voteItem){
Integer oldVoteCount = mapVoteCount.get(user);
if(oldVoteCount == null){
oldVoteCount = 0;
}
oldVoteCount += 1;
mapVoteCount.put(user,oldVoteCount);
if(oldVoteCount == 1){
state = new NormalVote();
} else if (oldVoteCount > 1 && oldVoteCount < 5) {
state = new RepeatVoteState();
} else if (oldVoteCount >= 5 && oldVoteCount < 8) {
state = new SpiteVoteState();
} else if (oldVoteCount > 8) {
state = new BlackVoteState();
}
state.vote(user,voteItem,this);
}
}
//客户端
public class Client {
public static void main(String[] args) {
VoteManager voteManager = new VoteManager();
for(int i = 0;i<9;i++){
voteManager.vote("u1","abc");
}
}
}

运行结果如下:

恭喜投票成功

请不要重复投票

请不要重复投票

请不要重复投票

你有恶意刷屏行为,取消投票资格

你有恶意刷屏行为,取消投票资格

你有恶意刷屏行为,取消投票资格

你有恶意刷屏行为,取消投票资格

进入黑名单,将禁止登录和使用本系统