Java设计模式--组合模式

组合模式

将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使用户对单个对象和组合对象的使用具有一致性。

Composite Pattern

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

类图

模式的结构与使用

组合方法模式的结构中包括三种角色。

  • 抽象组件(Abstract Component):是一个接口(抽象类),该接口(抽象类)定义了个体对象和组合对象需要实现的关于操作其子节点的方法,比如add()、remove()以及getChild()等方法。抽象组件也可以定义个体对象和组合对象用于操作其自身的方法,比如isLeaf()方法等。
  • Composite(Composite Node):实现Component接口类的实例,Composite节点不仅实现Component接口,而且可以含有其他Composite节点或Leaf节点的引用。
  • Leaf节点(Leaf Node):实现Component接口类的实例,Leaf节点实现Composite接口,不可以含有其他Composite节点或Leaf节点的引用,因此,叶节点在实现Component接口有关操作子节点的方法时,比如add()、remove()和getChild()方法,可让方法抛出一个异常,也可以实现为空操作。

简单的例子

Component的接口类MilitaryPerson.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package Component;
import java.util.Iterator;
public interface MilitaryPerson {
public void add(MilitaryPerson person);
public void remove(MilitaryPerson person);
public MilitaryPerson getChild(int index);
public Iterator<MilitaryPerson> getAllChildren();
public boolean isLeaf();
public double getSalary();
public void setSalary(double salary);
}

Composite的实现类MilitaryOfficer.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
package Component;
import java.util.Iterator;
import java.util.LinkedList;
public class MilitaryOfficer implements MilitaryPerson {
LinkedList<MilitaryPerson> list;
String name;
double salary;
public MilitaryOfficer(String name, double salary) {
this.name = name;
this.salary = salary;
list = new LinkedList<MilitaryPerson>();
}
@Override
public void add(MilitaryPerson person) {
list.add(person);
}
@Override
public void remove(MilitaryPerson person) {
list.remove(person);
}
@Override
public MilitaryPerson getChild(int index) {
return list.get(index);
}
@Override
public Iterator<MilitaryPerson> getAllChildren() {
return list.iterator();
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public double getSalary() {
return salary;
}
@Override
public void setSalary(double salary) {
this.salary = salary;
}
}

Leaf的实现类MilitarySoldier.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
package Component;
import java.util.Iterator;
public class MilitarySoldier implements MilitaryPerson {
double salary;
String name;
public MilitarySoldier(double salary, String name) {
this.salary = salary;
this.name = name;
}
@Override
public void add(MilitaryPerson person) {}
@Override
public void remove(MilitaryPerson person) {}
@Override
public MilitaryPerson getChild(int index) {
return null;
}
@Override
public Iterator<MilitaryPerson> getAllChildren() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
@Override
public double getSalary() {
return salary;
}
@Override
public void setSalary(double salary) {
this.salary = salary;
}
}

计算工资的工具类ComputerSalary.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package Component;
import java.util.Iterator;
public class ComputerSalary {
public static double computerSalary(MilitaryPerson person) {
double sum = 0;
if (person.isLeaf() == true) {
sum = sum + person.getSalary();
}
if (person.isLeaf() == false) {
sum = sum + person.getSalary();
Iterator<MilitaryPerson> iterator = person.getAllChildren();
while (iterator.hasNext()) {
MilitaryPerson p = iterator.next();
sum = sum + computerSalary(p);
}
}
return sum;
}
}

测试类Application.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
package Component;
public class Application {
public static void main(String[] args) {
MilitaryPerson 连长 = new MilitaryOfficer("连长", 5000);
MilitaryPerson 排长1 = new MilitaryOfficer("一排长", 4000);
MilitaryPerson 排长2 = new MilitaryOfficer("二排长", 4000);
MilitaryPerson 排长3 = new MilitaryOfficer("三排长", 4000);
MilitaryPerson 班长11 = new MilitaryOfficer("一排长", 2000);
MilitaryPerson 班长12 = new MilitaryOfficer("二排长", 2000);
MilitaryPerson 班长13 = new MilitaryOfficer("三排长", 2000);
MilitaryPerson 班长21 = new MilitaryOfficer("一排长", 2000);
MilitaryPerson 班长22 = new MilitaryOfficer("二排长", 2000);
MilitaryPerson 班长23 = new MilitaryOfficer("三排长", 2000);
MilitaryPerson 班长31 = new MilitaryOfficer("一排长", 2000);
MilitaryPerson 班长32 = new MilitaryOfficer("二排长", 2000);
MilitaryPerson 班长33 = new MilitaryOfficer("三排长", 2000);
MilitaryPerson[] 士兵 = new MilitarySoldier[90];
for (int i = 0; i < 士兵.length; i++) {
士兵[i] = new MilitarySoldier(1000, "小兵");
}
连长.add(排长1);
连长.add(排长2);
排长1.add(班长11);
排长1.add(班长12);
排长1.add(班长13);
排长2.add(班长21);
排长2.add(班长22);
排长2.add(班长23);
排长3.add(班长31);
排长3.add(班长32);
排长3.add(班长33);
for (int i = 0; i <= 9; i++) {
班长11.add(士兵[i]);
班长12.add(士兵[i + 10]);
班长13.add(士兵[i + 20]);
班长21.add(士兵[i + 30]);
班长22.add(士兵[i + 40]);
班长23.add(士兵[i + 50]);
班长31.add(士兵[i + 60]);
班长32.add(士兵[i + 70]);
班长33.add(士兵[i + 80]);
}
System.out.println("一排的军饷:" + ComputerSalary.computerSalary(排长1));
System.out.println("一班的军饷:" + ComputerSalary.computerSalary(班长11));
System.out.println("全连的军饷:" + ComputerSalary.computerSalary(连长));
}
}

执行效果图

组合模式的优点

  • 组合模式中包含个体对象和组合对象,并形成树形结构,使用户可以方便地处理个体对象和组合对象。
  • 组合对象和个体对象实现了相同的接口,用户一般无须区分个体对象和组合对象。
  • 当增加新的Composite节点和Leaf节点时,用户的重要代码不需要作出修改,例如,如果增加一个创建企业领导和一般职员的Composite节点和Leaf节点,那么ComputerSalary并不需要修改,就可以计算一个部门的薪水总和。

适用组合模式的情景

  • 当想表示对象的部分-整体层次结构。
  • 希望用户用一致的方式处理个体对象和组合对象。

下载源码请到

MyGitHub

Java设计模式--桥接模式

桥接模式(别名:柄体模式)

将抽象部分于它的实现部分分离,使它们都可以独立地变化。

Bridge Pattern(Another Name:Handle-Body)

Decouple an abstraction from its implementation so that the two can vary independently.

类图

模式的结构与使用

桥接模式的结构中包括四种角色。

  • 抽象(Abstraction):是一个抽象类,该抽象类含有Implementor声明的变量,即维护一个Implementor类型对象。
  • 实现者(Implementor):实现者角色是一个接口(抽象类),该接口(抽象类)中的方法不一定与Abstraction类中的方法一致。Implementor接口(抽象类)负责定义基本操作,而Abstraction类负责定义基于这些基本操作的较高层次的操作。
  • 细化抽象(Refined Abstration):细化抽象是抽象角色的一个子类,该子类在重写(覆盖)抽象角色中的抽象方法时,在给出一些必要的操作后,将委托所维护Implementor类型对象调用相应的方法。
  • 具体实现者(Concrete Implementor):具体实现者是实现(扩展)Implementor接口(抽象类)的类。

简单的例子

Abstract Template的抽象类CCTV.java

1
2
3
4
5
6
7
8
package Bridge;
import javax.swing.JPanel;
public abstract class CCTV extends JPanel {
Program programMaker;
public abstract void makeProgram();
}

Abstract Template的实现类CCTV5.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
package Bridge;
import java.awt.BorderLayout;
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.JLabel;
public class CCTV5 extends CCTV implements Runnable {
JLabel showFilm;
Thread thread;
ArrayList<String> content;
public CCTV5(Program program) {
programMaker = program;
setLayout(new BorderLayout());
showFilm = new JLabel("CCTV5频道");
showFilm.setFont(new Font("", Font.BOLD, 39));
add(showFilm, BorderLayout.CENTER);
thread = new Thread(this);
}
@Override
public void makeProgram() {
content = programMaker.makeTVProgram();
if (!thread.isAlive()) {
thread = new Thread(this);
thread.start();
}
}
@Override
public void run() {
for (int i = 0; i < content.size(); i++) {
showFilm.setText(content.get(i));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Abstract Template的实现类CCTV6.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
package Bridge;
import java.awt.BorderLayout;
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.JLabel;
public class CCTV6 extends CCTV implements Runnable {
JLabel showFilm;
Thread thread;
ArrayList<String> content;
public CCTV6(Program program) {
programMaker = program;
setLayout(new BorderLayout());
showFilm = new JLabel("CCTV6频道");
showFilm.setFont(new Font("", Font.BOLD, 39));
add(showFilm, BorderLayout.CENTER);
thread = new Thread(this);
}
@Override
public void makeProgram() {
content = programMaker.makeTVProgram();
if (!thread.isAlive()) {
thread = new Thread(this);
thread.start();
}
}
@Override
public void run() {
for (int i = 0; i < content.size(); i++) {
showFilm.setText(content.get(i));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Implementor的接口类Program.java

1
2
3
4
5
6
7
package Bridge;
import java.util.ArrayList;
public interface Program {
public ArrayList<String> makeTVProgram();
}

Implementor的实现类AthleticProgram.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package Bridge;
import java.util.ArrayList;
public class AthleticProgram implements Program {
ArrayList<String> content;
public AthleticProgram() {
content = new ArrayList<String>();
}
@Override
public ArrayList<String> makeTVProgram() {
content.clear();
content.add("足球直播");
content.add("篮球直播");
content.add("羽毛球直播");
content.add("兵乓球直播");
content.add("直播结束");
return content;
}
}

Implementor的实现类FilmProgram.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package Bridge;
import java.util.ArrayList;
public class FilmProgram implements Program {
ArrayList<String> content;
public FilmProgram() {
content = new ArrayList<String>();
}
@Override
public ArrayList<String> makeTVProgram() {
content.clear();
content.add("惊天魔盗团");
content.add("兵临城下");
content.add("海芋恋");
content.add("寒战");
content.add("电影结束");
return content;
}
}

测试类Application.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
package Bridge;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Application extends JFrame {
JButton seeProgram;
CCTV cctv;
Program program;
public Application(CCTV tv, Program program) {
this.cctv = tv;
this.program = program;
add(cctv, BorderLayout.CENTER);
seeProgram = new JButton("看节目");
add(seeProgram, BorderLayout.SOUTH);
seeProgram.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cctv.makeProgram();
}
});
setVisible(true);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public static void main(String[] args) {
Program program = new AthleticProgram();
CCTV cctv = new CCTV5(program);
Application application1 = new Application(cctv, program);
application1.setBounds(10, 10, 200, 300);
program = new FilmProgram();
cctv = new CCTV6(program);
Application application2 = new Application(cctv, program);
application2.setBounds(220, 10, 200, 300);
}
}

运行截图

桥接模式的优点

  • 桥接模式分离实现与抽象,使抽象和实现可以独立的扩展。当修改实现的代码时,不影响抽象的代码,反之也一样。
  • 满足开闭-原则。抽象和实现者处于同层次,使系统可独立地扩展这两个层次。增加新的具体实现者,不需要修改细化抽象,反之增加新的细化抽象也不需要修改具体实现。

适用桥接模式的情景

  • 不想让抽象和某些重要的实现代码是固定的绑定关系,这部分实现可运行时动态决定。
  • 抽象和实现者都可以继承的方式独立地扩充而互不影响,程序在运行期间可能需要动态的将一个抽象的子类的实例与一个实现者的子类的实例进行结合。
  • 希望对实现者层次代码的修改对抽象层不产生影响,即抽象层的代码不必重新编译,反之亦然。

下载源码请到

MyGitHub

Java设计模式--模板方法模式

模板方法模式

定义一个操作中算法的骨架,而将一些步骤延迟到子类中。模板方法使子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

Template Method Pattern

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

类图

模式的结构与使用

模板方法方法模式的结构中包括两种角色。

  • 抽象模板(Abstract Template):抽象模板是一个抽象类。抽象模板定义了若干个方法以表示一个算法的各个步骤,这些方法中有抽象方法也有非抽象方法,其中的抽象方法称作原语操作(Primitive Operation)。重要的一点是,抽象模板中还定义了一个称作模板方法的方法,该方法不仅包含有抽象模板中表示算法步骤的方法调用,而且也可以包含有定义在抽象模板中的其他对象的方法调用,即模板方法定义了算法的骨架。
  • 具体模板(Concrete Template):具体模板是抽象模板的子类,实现抽象模板中的原语操作。

简单的例子

Abstract Template的抽象类AbstractTemplate.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package TemplateMethod;
import java.io.File;
public abstract class AbstractTemplate {
File[] allFiles;
File dir;
public AbstractTemplate(File dir) {
this.dir = dir;
}
public final void showFileName() {
allFiles = dir.listFiles();
sort();
printFiles();
}
public abstract void sort();
public abstract void printFiles();
}

Abstract Template的实现类ConcreteTemplate1.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
package TemplateMethod;
import java.io.File;
import java.sql.Date;
import java.text.SimpleDateFormat;
public class ConcreteTemplate1 extends AbstractTemplate {
public ConcreteTemplate1(File dir) {
super(dir);
}
@Override
public void sort() {
for (int i = 0; i < allFiles.length; i++) {
for (int j = i + 1; j < allFiles.length; j++) {
if (allFiles[j].lastModified() < allFiles[i].lastModified()) {
File file = allFiles[j];
allFiles[j] = allFiles[i];
allFiles[i] = file;
}
}
}
}
@Override
public void printFiles() {
for (int i = 0; i < allFiles.length; i++) {
long time = allFiles[i].lastModified();
Date date = new Date(time);
SimpleDateFormat matter = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
String str = matter.format(date);
String name = allFiles[i].getName();
int k = i + 1;
System.out.println(k + " " + name + "(" + str + ")");
}
}
}

Abstract Template的实现类ConcreteTemplate2.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
package TemplateMethod;
import java.io.File;
public class ConcreteTemplate2 extends AbstractTemplate {
public ConcreteTemplate2(File dir) {
super(dir);
}
@Override
public void sort() {
for (int i = 0; i < allFiles.length; i++) {
for (int j = i + 1; j < allFiles.length; j++) {
if (allFiles[j].lastModified() < allFiles[i].lastModified()) {
File file = allFiles[j];
allFiles[j] = allFiles[i];
allFiles[i] = file;
}
}
}
}
@Override
public void printFiles() {
for (int i = 0; i < allFiles.length; i++) {
long fileSize = allFiles[i].length();
String name = allFiles[i].getName();
int k = i + 1;
System.out.println(k + " " + name + "(" + fileSize + "字节)");
}
}
}

测试类Application.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package TemplateMethod;
import java.io.File;
public class Application {
public static void main(String[] args) {
File dir = new File("d:/java/masm5");
AbstractTemplate template = new ConcreteTemplate1(dir);
System.out.println(dir.getPath() + "目录下的文件:");
template.showFileName();
template = new ConcreteTemplate2(dir);
System.out.println(dir.getPath() + "目录下的文件:");
template.showFileName();
}
}

执行效果图

电脑目录下文件截图

钩子方法

有时间一定补,不过下面优点介绍了一点钩子的好处

模板方法模式的优点

  • 可以通过在抽象模板定义模板方法给出成熟的算法步骤,同时又不限制步骤的细节,具体模板实现算法细节不会改变整个算法的骨架。
  • 在抽象模板模式中,可以通过钩子方法对某些步骤进行挂钩,具体模板通过钩子可以选择算法骨架中的某些步骤。

适用模板方法模式的情景

  • 设计者需要给出一个算法的固定步骤,并将某些步骤的具体实现留给子类来实现。
  • 需要对代码进行重构,将各个子类公共行为提取出来集中到一个共同的父类中以避免代码重复。

下载源码请到

MyGitHub

Java设计模式--代理模式

代理模式

为其他对象提供一种代理以控制对这个对象的访问。

Proxy Pattern

Provide a surrogate or placeholder for another object to control access to it.

类图

模式的结构与使用

代理方法模式的结构中包括三种角色。

  • 抽象主题(Subject):抽象主题是一个接口,该接口是对象和它的代理所共用的接口,即是RealSubject角色和Proxy角色实例所实现的接口。
  • 实际主题(RealSubject):实际主题是实现抽象主题接口的类。实际主题的实例是代理角色(Proxy)实例所要代理的对象。
  • 代理(Proxy):代理是实现抽象主题接口的类(代理和实际主题实现了相同的接口)。代理含有主题接口声明的变量,该变量用来存放RealSubject角色的实例引用,这样一来,代理的实例就可以控制对它所包含的RealSubject角色的实例访问,即可以控制对它所代理对象的访问。

简单的例子

Subject的接口类Geometry.java

1
2
3
4
5
package Proxy;
public interface Geometry {
public double getArea();
}

RealSubject的实现类Triangle.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package Proxy;
public class Triangle implements Geometry {
double sideA, sideB, sideC, area;
public Triangle(double sideA, double sideB, double sideC) {
this.sideA = sideA;
this.sideB = sideB;
this.sideC = sideC;
}
@Override
public double getArea() {
double p = (sideA + sideB + sideC) / 2.0;
area = Math.sqrt(p * (p - sideA) * (p - sideB) * (p - sideC));
return area;
}
}

Proxy的实现类TriangleProxy.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
package Proxy;
public class TriangleProxy implements Geometry {
double sideA, sideB, sideC;
Triangle triangle;
public void setABC(double a, double b, double c) {
sideA = a;
sideB = b;
sideC = c;
}
@Override
public double getArea() {
if (sideA + sideB > sideC && sideA + sideC > sideB
&& sideB + sideC > sideA) {
triangle = new Triangle(sideA, sideB, sideC);
double area = triangle.getArea();
return area;
} else
return -1;
}
}

测试类Application.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Proxy;
import java.util.Scanner;
public class Application {
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
System.out.println("请输入三个数");
double a,b,c;
a = reader.nextDouble();
b = reader.nextDouble();
c = reader.nextDouble();
TriangleProxy tp = new TriangleProxy();
tp.setABC(a, b, c);
System.out.println("面积是:" + tp.getArea());
}
}

执行效果图

远程代理

先空着,有时间补

代理模式的优点

  • 使用代理模式可以让用户的代码和某个特定类的子类的代码解耦。
  • 代理方法的使用用户不必知道它所使用的对象是怎么被创建的,只需要知道该对象有哪些方法即可。

适用代理模式的情景

  • 用户需要一个类的子类的实例,但不希望与该类的子类形成耦合。
  • 用户需要一个类的子类的实例,但用户不知道该类有哪些子类可用。

下载源码请到

MyGitHub

Java设计模式--访问者模式

访问者模式(别名:虚拟构造)

表示一个作用于某对象结构中的各个元素的操作。它可以在不改变各个元素的类的前提下定义作用于这些元素的新操作。

Visitor Pattern

Represent an operation to be preformed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operator.

类图

模式的结构与使用

访问者模式的结构中包括五种角色。

  • 抽象元素(Element):一个抽象类,该类定义了接口访问者的accept操作。
  • 具体元素(Concrete Element):Element的子类。
  • 对象结构(Object Structure):一个集合,用于存放Element对象,提供遍历它自己的方法。
  • 抽象访问者(Visitor):一个接口,该接口定义操作对象(Concrete Element的实例)的方法。

简单的例子

Element的抽象类Student.java

1
2
3
4
5
package Visitor;
public abstract class Student {
public abstract void accept(Visitor v);
}

ConcreteElement的实现类GraduateStudent.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
package Visitor;
public class GraduateStudent extends Student {
private double math,english,physics;
private String name;
public GraduateStudent(double math, double english, double physics,
String name) {
this.math = math;
this.english = english;
this.physics = physics;
this.name = name;
}
public double getMath() {
return math;
}
public double getEnglish() {
return english;
}
public double getPhysics() {
return physics;
}
public String getName() {
return name;
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
}

ConcreteElement的实现类Undergraduate.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
package Visitor;
public class Undergraduate extends Student {
private double math,english;
private String name;
public Undergraduate(double math, double english, String name) {
this.math = math;
this.english = english;
this.name = name;
}
public double getMath() {
return math;
}
public double getEnglish() {
return english;
}
public String getName() {
return name;
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
}

Visitor的接口类Visitor.java

1
2
3
4
5
6
package Visitor;
public interface Visitor {
public void visit(Undergraduate stu);
public void visit(GraduateStudent stu);
}

ConcreteVisitor的实现类Company.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package Visitor;
public class Company implements Visitor {
@Override
public void visit(Undergraduate stu) {
double math = stu.getMath();
double english = stu.getEnglish();
if (math > 80 && english > 90) {
System.out.println(stu.getName() + "被录用");
}
}
@Override
public void visit(GraduateStudent stu) {
double math = stu.getMath();
double english = stu.getEnglish();
double physics = stu.getPhysics();
if (math > 80 && english > 90 && physics > 70) {
System.out.println(stu.getName() + "被录用");
}
}
}

测试类Application.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package Visitor;
import java.util.ArrayList;
import java.util.Iterator;
public class Application {
public static void main(String[] args) {
Visitor visitor = new Company();
ArrayList<Student> studentList = new ArrayList<Student>();
studentList.add(new Undergraduate(88, 67, "张三"));
studentList.add(new Undergraduate(90, 98, "李四"));
studentList.add(new Undergraduate(85, 92, "王五"));
studentList.add(new GraduateStudent(88, 70, 87, "赵六"));
studentList.add(new GraduateStudent(90, 95, 82, "周吴"));
Iterator<Student> iter = studentList.iterator();
while (iter.hasNext()) {
Student stu = iter.next();
stu.accept(visitor);
}
}
}

执行效果图

双重分派

访问者模式在不改变类的情况下可有效地增加其上的操作,为了达到这样的效果,使用了一种称为“双重分派”的技术:在访问者模式中,被访问者,即Element角色element,首先调用accept(Visitor visitor)方法接受访问者,而被接受的访问者visitor再调用visit(Element element)方法访问当前对象。

访问者模式的优点

  • 可以在不改变一个集合中元素的类的情况下,增加新的施加于该元素上的新操作。
  • 可以将集合中各个元素的某些操作集中到访问者中,不仅便于集合的维护,也有利于集合中元素的复用。
    注:在访问者模式中,每增加一个Element角色的子类,都意味着需要在Visitor角色中给出访问该子类的实例的visit()的方法。

适用访问者模式的情景

  • 一个对象结构中,比如某个集合中,包含很多对象,想对集合中的对象增加一些新的操作。
  • 需要对集合中的对象进行很多不同的并且不相关的操作,而又不想修改对象的类,就可以使用访问者模式。访问者模式可以在Visitor类中集中定义一些关于集合中对象的操作。

下载源码请到

MyGitHub

Java设计模式--解释器模式

解释器模式

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

Interpreter Pattern

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

类图

模式的结构与使用

解释器模式的结构中包括四个角色。

  • 抽象表达式(AbstractExpression):该角色为一个接口,负责定义抽象的解释操作。
  • 终结符表达式(TerminalExpression):实现AbstractExpression接口的类。该类将接口中的解释器操作实现为与文法中的终结符相关联的操作,即文法中的每个终结符需要一个TerminalExpression类。
  • 非终结符表达式(NonterminalExpression):实现AbstractExpression接口的类。文法中的每一条规则R::=R1R2…Rn都需要一个NonterminalExpression类。NonterminalExpression类为文法中的非终结符号实现解释操作,该解释操作通常使用递归用表示Ri到Rn的那些对象的解释操作。
  • 上下文(Context):包含解释器之外的一些全局信息。

简单的例子

Node的接口类Dog.java

1
2
3
4
5
6
package Interpreter;
public interface Node {
public void parse(Context text);
public void execute();
}

Context的类Context.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
package Interpreter;
import java.util.StringTokenizer;
public class Context {
StringTokenizer tokenizer;
String token;
public Context(String text) {
setContext(text);
}
public void setContext(String text) {
tokenizer = new StringTokenizer(text);
}
String nextToken() {
if (tokenizer.hasMoreTokens()) {
token = tokenizer.nextToken();
} else
token = "";
return token;
}
}

Node的实现类SubjectPronounOrNounNode.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
package Interpreter;
public class SubjectPronounOrNounNode implements Node {
String[] word = {"You", "He", "Teacher", "Student"};
String token;
boolean boo;
@Override
public void parse(Context context) {
token = context.nextToken();
int i = 0;
for (; i < word.length; i++) {
if (token.equalsIgnoreCase(word[i])) {
boo = true;
break;
}
}
if (i == word.length) {
boo = false;
}
}
@Override
public void execute() {
if (boo) {
if (token.equalsIgnoreCase(word[0]))
System.out.print("你");
if (token.equalsIgnoreCase(word[1]))
System.out.print("他");
if (token.equalsIgnoreCase(word[2]))
System.out.print("老师");
if (token.equalsIgnoreCase(word[3]))
System.out.print("学生");
} else {
System.out.println(token + "(不是该语言中的语句)");
}
}
}

Node的实现类ObjectPronounOrNounNode.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
package Interpreter;
public class ObjectPronounOrNounNode implements Node {
String[] word = {"Me", "Him", "Tiger", "Apple"};
String token;
boolean boo;
@Override
public void parse(Context context) {
token = context.nextToken();
int i = 0;
for (; i < word.length; i++) {
if (token.equalsIgnoreCase(word[i])) {
boo = true;
break;
}
}
if (i == word.length) {
boo = false;
}
}
@Override
public void execute() {
if (boo) {
if (token.equalsIgnoreCase(word[0]))
System.out.print("我");
if (token.equalsIgnoreCase(word[1]))
System.out.print("他");
if (token.equalsIgnoreCase(word[2]))
System.out.print("老虎");
if (token.equalsIgnoreCase(word[3]))
System.out.print("苹果");
} else {
System.out.println(token + "(不是该语言中的语句)");
}
}
}

Node的实现类VerbNode.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
package Interpreter;
public class VerbNode implements Node {
String[] word = {"Drink", "Eat", "Look", "beat"};
String token;
boolean boo;
@Override
public void parse(Context context) {
token = context.nextToken();
int i = 0;
for (; i < word.length; i++) {
if (token.equalsIgnoreCase(word[i])) {
boo = true;
break;
}
}
if (i == word.length) {
boo = false;
}
}
@Override
public void execute() {
if (boo) {
if (token.equalsIgnoreCase(word[0]))
System.out.print("喝");
if (token.equalsIgnoreCase(word[1]))
System.out.print("吃");
if (token.equalsIgnoreCase(word[2]))
System.out.print("看");
if (token.equalsIgnoreCase(word[3]))
System.out.print("打");
} else {
System.out.println(token + "(不是该语言中的语句)");
}
}
}

Node的实现类SubjectNode.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package Interpreter;
public class SubjectNode implements Node {
Node node;
@Override
public void parse(Context text) {
node = new SubjectPronounOrNounNode();
node.parse(text);
}
@Override
public void execute() {
node.execute();
}
}

Node的实现类PredicateNode.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
papackage Interpreter;
public class PredicateNode implements Node {
Node verbNode, objectNode;
@Override
public void parse(Context text) {
verbNode = new VerbNode();
objectNode = new ObjectPronounOrNounNode();
verbNode.parse(text);
objectNode.parse(text);
}
@Override
public void execute() {
verbNode.execute();
objectNode.execute();
}
}

Node的实现类SentenceNode.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package Interpreter;
public class SentenceNode implements Node {
Node subjectNode, predicateNode;
@Override
public void parse(Context text) {
subjectNode = new SubjectNode();
predicateNode = new PredicateNode();
subjectNode.parse(text);
predicateNode.parse(text);
}
@Override
public void execute() {
subjectNode.execute();
predicateNode.execute();
}
}

测试类Application.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package Interpreter;
public class Application {
public static void main(String[] args) {
String text = "Teacher beat tiger";
Context context = new Context(text);
Node node = new SentenceNode();
node.parse(context);
node.execute();
System.out.println();
text = "You eat apple";
context.setContext(text);
node.parse(context);
node.execute();
}
}

运行结果

老师打老虎
你吃苹果

解释器模式的优点

  • 将每一个语法规则表示成一个类,方便于实现简单的语言。
  • 由于使用类表示语法规则,可以较容易改变或扩展语言的行为。
  • 通过在类结构中加入新的方法,可以在解释的同时增加新的行为。

适用解释器模式的情景

  • 当有一个简单的语言需要解释执行,并且可以将该语言的每一个规则表示为一个类时,就可以使用解释模式。
注意:如果文法过于复杂,那么过多的文法规则使我们很艰难维护所给出的类。

下载源码请到

MyGitHub

Java设计模式--备忘录模式

备忘录模式(别名:标记)

在不破坏封装性的前提下,捕捉一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。

Memento Pattern(Another Name: Token)

Without violating encapsulation, capture and externalize an object original state so that the object can be restored to this state later.

类图

模式的结构与使用

备忘录模式的结构中包括三种角色。

  • 原发者(Originator):需要在某个时刻保存其状态的对象。原发者负责创建备忘录,比如使用createMemento()方法创建一个备忘录,然后原发者使用该备忘录记录自己的状态。当原发者需要恢复某个时刻的状态时,它通过获得相应备忘录中的数据来恢复那个时刻的状态,比如原发者调用restoreFromMemento(Memento menm)方法,并通过参数mem指定的备忘录恢复状态。
  • 备忘录(Memento):负责存储原发者状态的对象,创建备忘录的类和创建原发者的类在同一个包中,该类提供的访问数据的方法都是友好方法,使得只有和原发者在同一个包中的类的实例才可以访问备忘录中的数据。
  • 负责人(Caretaker):负责管理保存备忘录的对象。负责人如果不和原发者在同一个包中,就不能对备忘录中的内容进行修改或读取。如果需要将备忘录保存到磁盘,负责人可以使用对象流将备忘录写入文件。

简单的例子

Memento的备忘录类Memento.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package Memento;
import java.io.Serializable;
public class Memento implements Serializable {
private long state;
void setPositionState(long state) {
this.state = state;
}
long getPosition() {
return state;
}
}

一个小的工具类ReadPhrase.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
ppackage Memento;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class ReadPhrase {
long readPosition;
File file;
RandomAccessFile in;
String phrase = null;
public ReadPhrase(File file) {
this.file = file;
try {
in = new RandomAccessFile(file, "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public Memento createMemento() {
Memento mem = new Memento();
System.out.println("----" + readPosition);
mem.setPositionState(readPosition);
return mem;
}
public void restoreFromMemento(Memento mem) {
readPosition = mem.getPosition();
}
public String readLine() {
try {
in.seek(readPosition);
phrase = in.readLine();
if (phrase != null) {
byte b[] = phrase.getBytes("UTF-8");
phrase = new String(b);
}
readPosition = in.getFilePointer();
System.out.println("readPosition:" + readPosition);
} catch (IOException e) {
e.printStackTrace();
}
return phrase;
}
public void closeRead() {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

负责人的类Caretaker.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
package Memento;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Caretaker {
File file;
private Memento memento = null;
public Caretaker() {
file = new File("saveObject.txt");
}
public Memento getMemento() {
if (file.exists()) {
try {
FileInputStream in = new FileInputStream("saveObject.txt");
ObjectInputStream inObject = new ObjectInputStream(in);
memento = (Memento) inObject.readObject();
} catch (Exception e) {
e.printStackTrace();
}
}
return memento;
}
public void saveMemento(Memento memento) {
FileOutputStream out;
try {
out = new FileOutputStream("D:/09soft/MyEclipse 10/yanning/saveObject.txt");
ObjectOutputStream outObject = new ObjectOutputStream(out);
outObject.writeObject(memento);
} catch (Exception e) {
e.printStackTrace();
}
}
}

测试类Application.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
package Memento;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Scanner;
public class Application {
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
ReadPhrase readPhrase = new ReadPhrase(new File("D:/09soft/MyEclipse 10/yanning/src/Memento/phrase.txt"));
File favorPhrase = new File("favorPhrase.txt");
RandomAccessFile out = null;
try {
out = new RandomAccessFile(favorPhrase, "rw");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println("是否从上次读取的位置继续读取成语(输入y或n)");
String answer = reader.nextLine();
if (answer.startsWith("y")||answer.startsWith("Y")) {
Caretaker caretaker = new Caretaker(); //创建负责人
Memento memento = caretaker.getMemento(); //得到备忘录
if (memento != null) {
readPhrase.restoreFromMemento(memento); //使用备忘录恢复状态
}
String phrase = null;
while((phrase = readPhrase.readLine()) != null) {
System.out.println(phrase);
System.out.println("是否将该成语保存到" + favorPhrase.getName());
answer = reader.nextLine();
if (answer.startsWith("y")||answer.startsWith("Y")) {
try {
out.seek(favorPhrase.length());
byte[] b = phrase.getBytes();
out.write(b);
out.write(' ');
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("是否继续读取成语?(输入y或n)");
answer = reader.nextLine();
if (answer.startsWith("y")||answer.startsWith("Y")) {
continue;
} else {
readPhrase.closeRead();
caretaker.saveMemento(readPhrase.createMemento());
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
System.exit(0);
}
}
System.out.println("读完全部成语");
}
System.exit(0);
}
}

备忘录模式的优点

  • 备忘录模式使用备忘录可以把原发者的内部状态保存起来,使只有很“亲密的”的对象可以访问备忘录中的数据。
  • 备忘录模式强调了类设计单一责任原则,即将状态的刻画和保存分开。

适用备忘录模式的情景

下列情况之一就可以考虑使用备忘录模式

  • 必须保存一个对象在某一时刻的全部或部分状态,以便在需要时恢复该对象先前的状态。
  • 一个对象不想通过提供public权限的,诸如getXXX()的方法让其他对象得到自己的内部状态。

注:如果备忘录需要存储大量的数据或非常频繁地创建备忘录,可能会导致非常大的存储开销。

下载源码请到

MyGitHub

Java设计模式--享元模式

享元模式

运用共享技术有效的支持大量细粒度的对象。

Flyweight Pattern

Use sharing to support large numbers of fine-grained objects efficiently.

类图

模式的结构与使用

享元方法模式的结构中包括三种角色。

  • 享元接口(Flyweight):是一个接口,该接口定义了享元对外公开其内部数据的方法,以及享元接收外部数据的方法。
  • 具体享元(Concrete Flyweight):实现享元接口的类,该类的实例称为享元对象,或简称享元。具体享元类的成员变量为享元对象的内部状态,享元对象的内部状态必须与所处的周围环境无关,即要保证使用享元对象的应用程序无法更改享元的内部状态,只有这样才能使得享元对象在系统中被共享。因为享元对象是用来共享的,所以不能允许用户各自地使用具体享元类来创建对象,这样就无法达到共享的目的,因为不同用户用具体享元类创建的对象显然是不同的,所以,具体享元类的构造方法必须是private的,其目的是不允许用户程序直接使用具体享元类来创建享元对象,创建和管理享元对象由享元工厂负责。
  • 享元工厂(Flyweight Factory):享元工厂是一个类,该类的实例负责创建和管理享元对象,用户或其他对象必须请求享元工厂为它得到一个享元对象。享元工厂可以通过一个散列表(也称共享池)来管理享元对象,当用户程序或其他若干个对象向享元工厂请求一个享元对象时,如果享元工厂的散列表中已有这样的享元对象,享元工厂就提供这个享元对象给请求者,否则就创建一个享元对象添加到散列表中,同时该享元对象提供给请求者。显然,当若干个用户或对象请求享元工厂提供一个享元对象时,第一个用户获得该享元对象的时间可能慢一些,但是后继的用户会较快地获得这个享元对象。可以使用单例模式来设计享元工厂,即让系统中只有一个享元工厂的实例。另外,为了让享元工厂能生成享元对象,需要将具体享元类作为享元工厂的内部类。

简单的例子

Flyweight的抽象类Flyweight.java

1
2
3
4
5
6
7
8
package Flyweight;
public interface Flyweight {
public double getHeight(); //返回内部数据
public double getWidth();
public double getLength();
public void printMess(String mess); //使用参数mess获取外部数据
}

Flyweight Factory的实现类FlyweightFactory.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
66
67
68
69
package Flyweight;
import java.util.HashMap;
public class FlyweightFactory {
private HashMap<String, Flyweight> hashMap;
static FlyweightFactory factory = new FlyweightFactory();
public FlyweightFactory() {
this.hashMap = new HashMap<String, Flyweight>();
}
public static FlyweightFactory getFactory() {
return factory;
}
public synchronized Flyweight getFlyweight(String key) {
if (hashMap.containsKey(key)) {
return hashMap.get(key);
} else {
double width = 0,height = 0,lenght = 0;
String[] str = key.split("#");
width = Double.parseDouble(str[0]);
height = Double.parseDouble(str[1]);
lenght = Double.parseDouble(str[2]);
Flyweight ft = new ConcreteFlyweight(width, height, lenght);
hashMap.put(key, ft);
return ft;
}
}
class ConcreteFlyweight implements Flyweight {
private double width;
private double height;
private double lenght;
public ConcreteFlyweight(double width, double height, double lenght) {
this.width = width;
this.height = height;
this.lenght = lenght;
}
@Override
public double getHeight() {
return height;
}
@Override
public double getWidth() {
return width;
}
@Override
public double getLength() {
return lenght;
}
@Override
public void printMess(String mess) {
System.out.println(mess);
System.out.print("宽度:" + width);
System.out.print("高度:" + height);
System.out.print("长度:" + lenght);
}
}
}

需要使用共享数据的类Car.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
package Flyweight;
public class Car {
Flyweight flyweight;
String name, color;
int power;
public Car(Flyweight flyweight, String name, String color, int power) {
this.flyweight = flyweight;
this.name = name;
this.color = color;
this.power = power;
}
public void print() {
System.out.println("名称:" + name);
System.out.println("颜色:" + color);
System.out.println("功率:" + power);
System.out.println("宽度:" + flyweight.getWidth());
System.out.println("高度:" + flyweight.getHeight());
System.out.println("长度:" + flyweight.getLength());
}
}

测试类Application.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
package Flyweight;
public class Application {
public static void main(String[] args) {
FlyweightFactory factory = FlyweightFactory.getFactory();
double width = 1.82, height = 1.47, lenght = 5.12;
String key = "" + width + "#" + height + "#" + lenght;
Flyweight flyweight = factory.getFlyweight(key);
Car audiA60ne = new Car(flyweight, "奥迪A6", "黑色", 128);
Car audiA6Two = new Car(flyweight, "奥迪A6", "灰色", 160);
//audiA60ne和audiA6Two没有向享元传递外部数据,而是获取享元的内部数据
audiA60ne.print();
audiA6Two.print();
width = 1.77;
height = 1.45;
lenght = 4.63;
key = "" + width + "#" + height + "#" + lenght;
Car audiA40ne = new Car(flyweight, "奥迪A4", "蓝色", 126);
Car audiA4Two = new Car(flyweight, "奥迪A4", "红色", 138);
//audiA40ne和audiA4Two向享元传递外部数据,这些数据是不共享的
flyweight.printMess("名称: 奥迪A4 颜色:蓝色 功率:126");
flyweight.printMess("名称: 奥迪A4 颜色:红色 功率:138");
}
}

执行结果

享元模式的优点

  • 使用享元模式可以节省内存的开销,特别适合处理大量细粒度对象,这些对象的许多属性值是相同的,而且一旦创建则不容许修改。
  • 享元模式中的享元可以使用方法的参数接收外部状态中的数据,但外部状态数据不会干扰到享元中的内部数据,这就使享元可以在不同的环境中被共享。

适用享元模式的情景

下列情况之一就可以考虑使用享元模式:

  • 一个应用程序使用大量的对象,这些对象之间部分属性本质上是相同的,这时应使用享元来封装相同的部分。
  • 对象的多数状态都可变为外部状态,就可以考虑将这些对象作为系统中的享元来使用。

下载源码请到

MyGitHub

Java设计模式--状态模式

状态模式(别名:状态对象)

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

State Pattern(Another Name: Object for States)

Allow an object to alert its behavior when its internal state changes. The object will appear to change its class.

类图

模式的结构与使用

状态模式的结构中包括三种角色。

  • 环境(Context):环境是一个类,该类含有抽象状态(State)声明的变量,可以引用任何具体状态类的实例。用户对该环境(Context)类的实例在某种状态下的行为感兴趣。
  • 抽象状态(State):抽象状态是一个接口或抽象类。抽象状态中定义了与环境(Context)的一个特定状态相关的如果个方法。
  • 具体状态(Concrete State):具体状态是实现(扩展)抽象状态(抽象类)的类。

简单的例子

State的接口类TemperatureState.java

1
2
3
4
5
package State;
public interface TemperatureState {
public void showTemperature();
}

Context环境类Thermometer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package State;
public class Thermometer {
TemperatureState state;
public void showMessage() {
System.out.println("*************");
state.showTemperature();
System.out.println("*************");
}
public void setState(TemperatureState state) {
this.state = state;
}
}

ConcreteState的实现类LowState.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package State;
public class LowState implements TemperatureState {
double n = 0;
public LowState(double n) {
if (n < 0) {
this.n = n;
}
}
@Override
public void showTemperature() {
System.out.println("现在的温度是" + n + "属于低温度");
}
}

ConcreteState的实现类MiddleState.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package State;
public class MiddleState implements TemperatureState {
double n = 15;
public MiddleState(double n) {
if (n > 0 && n < 26) {
this.n = n;
}
}
@Override
public void showTemperature() {
System.out.println("现在的温度是" + n + "属于正常温度");
}
}

ConcreteState的实现类HighState..java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package State;
public class HighState implements TemperatureState {
double n = 39;
public HighState(double n) {
if (n > 26) {
this.n = n;
}
}
@Override
public void showTemperature() {
System.out.println("现在的温度是" + n + "属于高温");
}
}

测试类Application.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package State;
public class Application {
public static void main(String[] args) {
TemperatureState state = new LowState(-12);
Thermometer thermometer = new Thermometer();
thermometer.setState(state);
thermometer.showMessage();
state = new MiddleState(15);
thermometer.setState(state);
thermometer.showMessage();
state = new HighState(40);
thermometer.setState(state);
thermometer.showMessage();
}
}

状态模式的优点

  • 使用一个类封装对象的一种状态,很容易增加新的状态。
  • 在状态模式中,环境(Context)中不必出现大量的条件判断语句。环境(Context)实例所呈现的状态变得更加清晰、容易理解。
  • 使用状态模式可以让用户程序很方便地切换环境(Context)实例的状态。
  • 使用状态模式不会让环境(Context)的实例中出现内部状态不一致的情况。
  • 当状态对象没有实例变量时,环境(Context)的各个实例可以共享一个状态对象。

适用状态模式的情景

  • 一个对象的行为依赖于它的状态,并且它必须在运行时根据状态改变它的行为。
  • 需要编写大量的条件分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态。

下载源码请到

MyGitHub

Java设计模式--责任链模式

责任链模式

使多个对象都有机会都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

Chain of Responsibility Pattern

A void coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

类图

模式的结构与使用

责任链模式的结构中包括两种角色。

  • 处理者(Handler):处理者是一个接口,负责规定具体处理者处理用户请求的方法以及具体处理者设置后继对象的方法。
  • 具体处理者(Concrete Handler):具体处理者是实现处理者的类的实例。具体处理者通过调用处理者接口规定的方法处理用户的请求,即在接到用户的请求后,处理者将调用接口规定的方法,在执行该方法的过程中,如果发现能处理用户的请求,就处理有关数据,否则就反馈无法处理的信息给用户,然后将用户的请求传递给自己的后继对象。

简单的例子

Handler的抽象类Handler.java

1
2
3
4
5
6
package Handler;
public interface Handler {
public abstract void handleRequest(String number);
public abstract void setHandler(Handler handler);
}

ConcreteHandler的实现类Beijing.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
package Handler;
import java.util.ArrayList;
public class Beijing implements Handler {
private Handler handler;
private ArrayList<String> numberList;
public Beijing() {
numberList = new ArrayList<String>();
numberList.add("11029812340930034");
numberList.add("11029812340930033");
numberList.add("11029812340930032");
numberList.add("11029812340930031");
numberList.add("11029812340930030");
}
@Override
public void handleRequest(String number) {
if (numberList.contains(number)) {
System.out.println("该人在北京住");
} else {
System.out.println("该人不在北京住");
if (handler!=null) {
handler.handleRequest(number);
}
}
}
@Override
public void setHandler(Handler handler) {
this.handler = handler;
}
}

ConcreteHandler的实现类Shanghai.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
package Handler;
import java.util.ArrayList;
public class Shanghai implements Handler {
private Handler handler;
private ArrayList<String> numberList;
public Shanghai() {
numberList = new ArrayList<String>();
numberList.add("12029812340930034");
numberList.add("12029812340930033");
numberList.add("12029812340930032");
numberList.add("12029812340930031");
numberList.add("12029812340930030");
}
@Override
public void handleRequest(String number) {
if (numberList.contains(number)) {
System.out.println("该人住在上海");
} else {
System.out.println("该人不住在上海");
if (handler!=null) {
handler.handleRequest(number);
}
}
}
@Override
public void setHandler(Handler handler) {
this.handler = handler;
}
}

测试类Application.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package Handler;
public class Application {
private Handler beijing,shanghai;
public void createChain() {
beijing = new Beijing();
shanghai = new Shanghai();
beijing.setHandler(shanghai);
}
public void reponseClient(String number) {
beijing.handleRequest(number);
}
public static void main(String[] args) {
Application application = new Application();
application.createChain();
application.reponseClient("12029812340930034");
}
}

责任链模式的优点

  • 责任链中的对象只和自己的后继是低耦合关系,和其他对象毫无关联,这使得编写处理者对象以及创建责任链变得非常容易。
  • 当在处理者中分配职责时,责任链给应用程序更多的灵活性。
  • 应用程序可以动态地增加、删除处理者或重新指派处理者的职责。
  • 应用程序可以动态地改变处理者之间的先后顺序。
  • 使用责任链的用户不必知道处理者的信息,用户不会知道到底是哪个对象处理了它的请求。

适用责任链模式的情景

  • 有许多对象可以处理用户的请求,希望程序在运行期间自动确定处理用户的那个对象。
  • 希望用户不必明确指定接受者的情况下,向多个接受者的一个提交请求。
  • 程序希望动态制定可处理用户请求的对象集合。

下载源码请到

MyGitHub