设计模式

本文是对软考中设计模式的整理

一. 设计模式介绍

1. 目的

复用成功的设计和体系结构

2. 基本要素

模式名称 问题 解决方案 效果

3. 分类

  • 创建型:与对象创建有关
  • 结构性:处理类与对象的组合
  • 行为型:对类或对象怎样交互和分配职责进行描述

二. 创建型模式

1. 简单工厂模式

用于创建实例的方法为静态方法

三类角色:

  • 工厂:负责实现创建所有产品的内部逻辑,可直接外部调用(采用static方法)
  • 抽象产品:产品的父类
  • 具体产品:实现抽象产品中声明的抽象方法

但是存在一个缺陷,如果后期想多加一种产品,需要改动工厂的方法,破坏了开闭原则(拓展开放,修改封闭)

2. 工厂方法模式

意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到子类

适用于:

  • 当一个子类不知道它所必须创建的对象的类
  • 当一个类希望由它子类指定它所创建的对象

3. 抽象工厂模式

意图:创建一系列相关或相互依赖对象的接口而无需指出他们的类

  • AbstractFactory声明一个创建抽象产品对象的操作接口
  • ConcreteFactory实现创建具体产品对象的操作
  • AbstractProduct为一类产品对象声明一个接口
  • ConcreteProduct定义一个将被相应的具体工厂创建的产品对象,实现抽象产品接口
  • Client仅使用抽象工厂和抽象产品类声明的接口

适用于:

  • 一个系统要独立于它的产品创建,组合和表示时
  • 一个系统要有多个产品系列中的一个来配置时
  • 当要强调一系列相关的产品对象的设计以便进行联合使用时
  • 当提供一个产品类库,只要显示它们的接口而不是实现时

抽象工厂声明一个创建组件的操作接口,具体工厂实现创建产品对象的操作

可以想成是qq中的各种主题,每个主题就是多个产品系列中的一种

4. 生成器模式

意图:将一个复杂的对象的构建与它的表示分离,使的同样的构建过程可以创建不同的表示

  • Builder为创建一个Product对象的各个部件指定抽象接口
  • ConcreteBuilder实现Builder的接口以构造和装配该产品的各个部件,定义并明确它创建的表示,提供一个检索产品的接口
  • Director构造一个使用Builder接口的对象
  • Product表示被构造的复杂对象(可使用List实现),ConcreteBuilder创建该产品的内部表示并定义它的装配过程

理解为买东西时可选的套餐

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
public class builder {
public static void main(String[] args) {
Concretebuild1 c1 = new Concretebuild1();
c1.builderpart();
Product p1 = c1.getResult();
p1.show();
}
}
abstract class build{
public abstract void builderpart();
public abstract Product getResult();
}
class Concretebuild1 extends build{
Product product = new Product();
@Override
public void builderpart() {
product.Add("A");
product.Add("B");
product.Add("C");
}
@Override
public Product getResult() {
return product;
}
}
class Product{
List<String> parts = new ArrayList<>();
public void Add(String part){
parts.add(part);
}
public void show(){
System.out.println(parts);
}
}

适用于:

  • 当创建复杂对象的算法应该独立于该对象的组成部分以及他们的装配方式时
  • 当构造过程必须允许被构造的对象有不同的表示时

5. 原型模式

意图:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象

  • Prototype声明一个复制自身的接口
  • ConcretePrototype实现一个复制自身的操作
  • Client让一个原型复制自身从而创建一个新的对象

类似在产品类中写一个深拷贝函数

代码实现中可以直接将产品类实现Cloneable接口(java提供的一个复制实例的接口)

适用于:

  • 当一个系统应该独立于它的产品创建,构成和表示时
  • 当要实例化的类是在运行时指定时,例如通过动态装载
  • 为了避免创建一个与产品类层次平行的工厂类层次时
  • 当一个类的实例只能有几个不同状态组合的一种时,建立相应数目的原型并克隆它们,可能比每次用合适的状态手工实例化该类更方便一些

6. 单例模式

意图:保证一个类只有一个实例,并提供一个访问它的全局访问点

适用于:

  • 当类只有一个实例而且客户可以从一个众所周知的访问点访问它时
  • 当这个唯一实例应该是通过子类化可拓展的,并且客户无须更改代码就能使用一个拓展的实例时

这个模式需要附加代码看看,加深理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class single {
public static void main(String[] args) {
//这里的s1和s2指向的都是那个唯一的实例
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
}
}
class Singleton{
private static Singleton instance = new Singleton();
//构造函数私有 外界则无法使用构造函数来new一个新的实例借此来实现唯一实例
private Singleton(){}
//提供一个全局访问点
public static Singleton getInstance(){
return instance;
}
}

三. 结构型模式

1. 适配器模式(对象)

适配器模式(类)不讨论

意图:将一个类的接口转化成客户希望的另外一个接口,Adapter模式使得原来由于接口不兼容而不能一起工作的那些类可以一起工作

代码部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class adapterpattern {
public static void main(String[] args) {
USB usb = new adapter();
usb.Request();
}
}
class USB{
public void Request(){
System.out.println("USB");
}
}
class adapter extends USB{
private TypeC t = new TypeC();
public void Request(){
t.SpecificRequest();
}
}
class TypeC{
public void SpecificRequest(){
System.out.println("typeC");
}
}

适用于:

  • 想使用一个已存在的类,而它的接口不符合要求
  • 想创建一个可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作
  • (仅使用对象Adapter)想使用一个已存在的子类,但是不可能对每一个都进行子类化以匹配他们的接口,对象适配器可以适配它们的父类接口

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
public class bridge {
public static void main(String[] args) {
productA p1 = new productA();
Color red = new Red();
p1.setColor(red);
p1.Operation();
}
}
abstract class product{
protected Color color;
public void setColor(Color color){
this.color = color;
}
public abstract void Operation();
}
class productA extends product{
@Override
public void Operation() {
color.OperationImp();
}
}
interface Color{
public void OperationImp();
}
class Red implements Color{
@Override
public void OperationImp() {
//具体上色操作
}
}

适用于:

  • 不希望在抽象和它的实现部分之间有一个固定的绑定关系,就像上面代码中产品的颜色属性单出来了
  • 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充,这是桥接模式使得开发者可以对不同的抽象接口和实现部分进行组合,并对它们进行扩充
  • 对一个抽象的实现部分的修改应对客户不产生影响,即客户不需要重新编译
  • 想在多个对象间共享实现,有许多类要生成的类层次结构

3. 组合模式

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

  • Component为组合中的对象声明接口,在适当情况下实现所有类共有的接口的默认行为,声明一个接口用于访问和管理Component的子组件,在递归结构中定义一个接口,用于访问一个父组件,并在合适的情况下实现它
  • Leaf在组合中表示叶节点对象,在组合中定义图元对象的行为
  • Composite定义有子组件的那些组件的行为,存储子组件,在Component接口中实现与子组件相关的操作
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
import java.util.ArrayList;
import java.util.List;
public class composite {
public static void main(String[] args) {

}
//遍历操作
static void print(AbstractFile file){
file.printName();
List<AbstractFile> childList = file.getChild();
if (childList==null) return;//避免是文件时list为空报错
for (AbstractFile child : childList){
print(child);
}
}
}
abstract class AbstractFile{
protected String name;
public void printName(){
System.out.println(name);
}
public abstract void Add(AbstractFile f);
public abstract void Remove(AbstractFile f);
public abstract List<AbstractFile> getChild();
}
class file extends AbstractFile{
@Override
public void Add(AbstractFile f) {
}
@Override
public void Remove(AbstractFile f) {
}
public file(String name){
this.name = name;
}
@Override
public List<AbstractFile> getChild() {
return null;
}
}
class folder extends AbstractFile{
private List<AbstractFile> childList = new ArrayList<AbstractFile>();
@Override
public void Add(AbstractFile f) {
childList.add(f);
}
@Override
public void Remove(AbstractFile f) {
childList.remove(f);
}
public folder(String name){
this.name = name;
}
@Override
public List<AbstractFile> getChild() {
return null;
}
}

适用于:

  • 想表示对象的部分-整体层次结构
  • 希望用户忽略组合对象(文件夹)与单个对象(文件)的不同,用户将统一地使用组合结构中地所有对象

4. 装饰器模式

意图:动态地给一个对象添加一些额外的职责,就增加功能而言,Decorator模式比生成子类更加灵活

  • Component定义一个对象接口,可以给这些对象动态地添加职责
  • ConcreteComponent定义一个对象,可以给这个对象添加一些职责
  • Decorator维持一个指向Component对象的指针,并定义一个与Component接口一致的接口
  • ConcreteDecorator向组件添加职责
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 class decorate {
public static void main(String[] args) {
Person zhangsan = new Student("张三");
zhangsan.Operation();//学习
zhangsan = new DecoratorA(zhangsan);
zhangsan.Operation();//学习 考试
//对象链
Person lisi = new DecoratorB(new DecoratorA(new Student("李四")));
lisi.Operation();//学习 考试 睡觉
}
}
abstract class Person{//Component
protected String name;
public abstract void Operation();//职责
}
class Student extends Person{
public Student(String name){
this.name = name;
}
@Override
public void Operation() {
//自己的职责
System.out.println("学习");
}
}
abstract class Decorator extends Person{
protected Person person;
}
class DecoratorA extends Decorator{
public DecoratorA(Person person){
this.person = person;
}
@Override
public void Operation() {
person.Operation();
//添加附加职责
System.out.println("考试");
}
}
class DecoratorB extends Decorator{
public DecoratorB(Person person){
this.person = person;
}
@Override
public void Operation() {
person.Operation();
//添加附加职责
System.out.println("睡觉");
}
}

适用于:

  • 在不影响其他对象的情况下,以动态透明的方式给单个对象添加职责
  • 处理那些可以撤销的职责
  • 当不能采用生成子类的方式进行扩充时

5. 外观模式

意图:为子系统中的一组接口提供一个一致的界面,facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用

  • Facade知道哪些子系统类负责处理请求;将客户的请求代理给适当的子系统对象
  • Subsystem classes实现子系统的功能;处理由facade对象指派的任务;没有Facade的任何相关信息,即没有指向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 facade {
public static void main(String[] args) {
Facade f = new Facade();
f.method1();
}
}
class Facade{
Subsystem1 s1;
Subsystem2 s2;
public Facade(){
s1 = new Subsystem1();
s2 = new Subsystem2();
}
public void method1(){
s1.method();
}
public void method2(){
s2.method();
}
}
class Subsystem1{
public void method(){
System.out.println("1");
}
}
class Subsystem2{
public void method(){
System.out.println("2");
}
}

适用于:

  • 要为一个复杂子系统提供一个简单接口时
  • 客户程序与抽象类的实现部分之间存在很大的依赖性
  • 当需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点

6. 代理模式

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

  • Proxy保存一个引用使得代理可以访问实体
  • Subject定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy
  • RealSubject定义Proxy所代表的实体
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 class proxy {
public static void main(String[] args) {
RealSubject r1 = new RealSubject();
proxylei p1 = new proxylei(r1);
p1.buy();
}
}
interface Subject{
public void buy();
}
class proxylei implements Subject{
protected RealSubject realSubject;
public proxylei(RealSubject realSubject){
this.realSubject = realSubject;
}
@Override
public void buy() {
System.out.println("办理手续");
realSubject.buy();
System.out.println("完成手续");
}
}
class RealSubject implements Subject{
@Override
public void buy() {
System.out.println("付钱");
}
}

适用于:

适用于在需要比较通用和复杂的对象指针代替简单的指针的时候

  • 远程代理为一个对象在不同地址空间提供局部代表
  • 虚代理根据需要创建开销很大的对象
  • 保护代理控制对原始对象的访问,用于对象应该有不同的访问权限的时候
  • 智能引用取代了简单指针,它在访问对象时执行一些附加操作

7. 享元模式(Flyweight)

意图:运用共享技术有效地支持大量细粒度的对象

细粒度:将业务模型中的对象加以细分

  • Flyweight描述一个接口,通过这个接口Flyweight可以接受并作用于外部状态
  • ConcreteFlyweight实现Flyweight接口并为内部状态增加存储空间,ConcreteFlyweight对象必须是可共享的,它所存储的状态必须是内部的,即他必须独立于ConcreteFlyweight对象的场景
  • 并非所有的Flyweight子类都需要共享,Flyweight接口使共享成为可能,但它并不强制共享,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点
  • FlyweightFactory创建并管理Flyweight对象,确保合理地共享Flyweight,当用户请求一个Flyweight时,会提供一个以创建的实例或者不存在时创建一个实例
  • Client维持一个对flyweight的引用,计算或存储一个或多个Flyweight的外部状态
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 class flyweight {
public static void main(String[] args) {
PlaceFactory p = new PlaceFactory();
Place w1 = p.getPlace(0);
w1.draw(1,2);
Place w2 = p.getPlace(0);
w2.draw(2,3);
//这里w1和w2是一个白棋实例
}
}
class PlaceFactory{
private Place[] places = {new white(),new black()};
public Place getPlace(int key){
if (key == 0) return places[0];
else return places[1];
}
}
abstract class Place{
protected String color;
public abstract void draw(int x,int y);
}
class white extends Place{
public white(){
this.color = "white";
}
@Override
public void draw(int x, int y) {
System.out.println(color + "x:"+x+"y"+y);
}
}
class black extends Place{
public black(){
this.color = "black";
}
@Override
public void draw(int x, int y) {
System.out.println(color + "x:"+x+"y"+y);
}
}

适用于:

  • 一个应用程序使用了大量的对象
  • 完全由于使用大量的对象造成很大的存储开销
  • 对象的大多数状态都可变为外部状态
  • 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象

四. 行为型模式

1. 责任链模式

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

  • Handler定义一个处理请求的接口
  • ConcreteHandler处理它所负责的请求,可访问它的后继者,如果可以处理该请求,就处理它,否则发送给它的后继者
  • Client向链上的具体处理者对象提交请求
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
public class Chain {
public static void main(String[] args) {
Handler f = new fudaoyuan();
Handler y = new yuanzhang();
Handler x = new xiaozhang();
f.setNext(y);
y.setNext(x);
}
}
abstract class Handler{
protected Handler next;
public void setNext(Handler next){
this.next = next;
}
public abstract void HandlerRequest(int request);
}
class fudaoyuan extends Handler{ // <= 7
@Override
public void HandlerRequest(int request) {
if (request<=7){
System.out.println("通过");
}else {
if (next!=null)
next.HandlerRequest(request);
else
System.out.println("办理失败");
}
}
}
class yuanzhang extends Handler{ // <= 15
@Override
public void HandlerRequest(int request) {
if (request<=15){
System.out.println("通过");
}else {
if (next!=null)
next.HandlerRequest(request);
else
System.out.println("办理失败");
}
}
}
class xiaozhang extends Handler{ // <= 30
@Override
public void HandlerRequest(int request) {
if (request<=30){
System.out.println("通过");
}else {
if (next!=null)
next.HandlerRequest(request);
else
System.out.println("办理失败");
}
}
}

适用于:

  • 有多个对象处理一个请求,哪个对象处理该请求运行时自动确定
  • 想在不明确指定接收者的情况下向多个对象中的一个提交一个请求
  • 可处理一个请求的对象集合应该被动态指定

2. 命令模式

意图:将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化,对请求排队或记录日志,以及支持可撤销的操作

  • Command声明执行操作的接口
  • ConcreteCommand将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute
  • Client创建一个具体命令对象并设定它的接收者
  • Invoker要求该命令执行这个请求
  • Receiver知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接收者
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 Command {
public static void main(String[] args) {
Invoker i = new Invoker();
TV tv = new TV();
com kai = new OnCommand(tv);
i.setComm(kai);
i.call();
}
}
class Invoker{//遥控器
private com comm;
public void setComm(com comm){
this.comm = comm;
}
public void call(){
comm.Execute();
}
}
interface com{
void Execute();//执行命令
}
class OnCommand implements com{
private TV tv;
public OnCommand(TV tv) {
this.tv = tv;
}
@Override
public void Execute() {//命令调用接收者行为
tv.kaiji();
}
}
class OffCommand implements com{
private TV tv;
public OffCommand(TV tv){
this.tv = tv;
}
@Override
public void Execute() {
tv.guanji();
}
}
class TV{//接收者 电视机
public void kaiji(){
System.out.println("开机");
}
public void guanji(){
System.out.println("关机");
}
}

适用于:

  • 抽象出待执行的动作以参数化某对象
  • 在不同的时刻指定,排列和执行请求
  • 支持取消操作
  • 支持修改日志

3. 解释器模式(Interpreter)

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

  • AbstractExpression声明一个程序的解释操作,这个接口为抽象语法树中所有的结点所共享
  • TerminalExpression实现与文法中的终结符相关联的解释操作,一个句子的每个终结符需要该类的一个实例
  • NonterminalExpression对文法中的每一条规则都需要一个NonterminalExpression类,为每个符号都维护一个AbstractExpression类型的实例变量,为文法中的非终结符实现解释操作
  • Context包含解释器之外的一些全局信息
  • Client构建表示该文法定义的语言中一个特定的句子的抽象语法树,该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成,调用解释操作
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 Interpreter {
public static void main(String[] args) {
context c = new context();
if (c.check("A区的开发")){
System.out.println("success");
}
}
}
class context{
private String[] regions = {"A区","B区","C区"};
private String[] personss = {"开发","测试","调试"};
private TerminalExpression t1 = new TerminalExpression(regions);
private TerminalExpression t2 = new TerminalExpression(personss);
private NonterminalExpression nt = new NonterminalExpression(t1,t2);
public boolean check(String info){
return nt.Interpret(info);
}
}
interface Expression{
boolean Interpret(String info);
}
class TerminalExpression implements Expression{
private Set<String> set = new HashSet<>();
public TerminalExpression(String[] data){
for(String str : data){
set.add(str);
}
}
@Override
public boolean Interpret(String info) {
return set.contains(info);
}
}
class NonterminalExpression implements Expression{
private TerminalExpression region;
private TerminalExpression person;
public NonterminalExpression(TerminalExpression region,TerminalExpression person){
this.region = region;
this.person = person;
}
@Override
public boolean Interpret(String info) {
String[] str = info.split("的");
return region.Interpret(str[0]) &&person.Interpret(str[1]);
}
}

适用于:

该模式适用于当有一个语言需要解释执行,并且可以将该语言中的句子表示为一个抽象的语法树时

  • 该文法简单
  • 效率不是一个关键问题

4. 迭代器模式(Iterator)

意图:提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示

  • Iterator(迭代器)定义访问和遍历元素的接口
  • ConcreteIterator(具体迭代器)实现迭代器接口,对该聚合遍历时跟踪当前位置
  • Aggregate(聚合)定义创建和实现迭代器对象的接口
  • ConcreteAggregate(具体聚合)实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例
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
public class diedaiqi {
public static void main(String[] args) {
ConcreteAggregate bookAggregate = new ConcreteAggregate();
String[] name = {"西游记","三国","水浒","红楼梦"};
double[] prices = {10.24,123.4,213.4,126};
for (int i=0;i<4;i++){
bookAggregate.Add(new Book(name[i],prices[i]));
}
Iterator bi = bookAggregate.CreateIterator();
while (bi.hasNext()){
Book b = (Book) bi.next();
System.out.println(b.getName()+" "+b.getPrice());
}
String[] name1 = {"五菱","宝马","奔驰","奥迪"};
double[] prices1 = {10.24,123.4,213.4,126};
ConcreteAggregate carAggregate = new ConcreteAggregate();
for (int i=0;i<4;i++){
carAggregate.Add(new car(name1[i],prices1[i]));
}
Iterator bi1 = carAggregate.CreateIterator();
while (bi1.hasNext()){
car b = (car) bi1.next();
System.out.println(b.getName()+" "+b.getPrice());
}
}
}
interface Iterator{
public boolean hasNext();
public Object next();
}
class ConcreteIterator implements Iterator{
private Aggregate aggregate;
private int index;
public ConcreteIterator(Aggregate aggregate){
index = 0;
this.aggregate = aggregate;
}
@Override
public boolean hasNext() {
return index<aggregate.getSize();
}
@Override
public Object next() {
return aggregate.get(index++);
}
}
interface Aggregate{
public Iterator CreateIterator();
public void Add(Object obj);
public int getSize();
public Object get(int index);
}
class ConcreteAggregate implements Aggregate{//聚合对象
private List<Object> list = new ArrayList<>();
public void Add(Object obj){
list.add(obj);
}
public Object get(int index){
return list.get(index);
}
public int getSize(){
return list.size();
}
@Override
public Iterator CreateIterator() {
return new ConcreteIterator(this);
}
}
class Book{
private String name;
private double price;
public Book(String name,double price){
this.name = name;
this.price = price;
}
public String getName(){
return name;
}
public double getPrice(){
return price;
}
}
class car{
private String name;
private double price;
car(String name, double price){
this.name = name;
this.price = price;
}
public String getName(){
return name;
}
public double getPrice(){
return price;
}
}

适用于:

  • 访问一个聚合对象的内容而无须暴露它的内部表示
  • 支持对聚合对象的多种遍历
  • 为遍历不同的聚合结构提供一个统一的接口

5. 中介者模式(Mediator)

意图:用一个中介对象来封装一系列对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互

  • Mediator(中介者)定义一个接口用于各同事(Colleague)对象通信。
  • ConcreteMediator(具体中介者)通过协调各同事对象实现协作行为;了解并维护它的各个同事。
  • Colleague class(同事类)知道它的中介者对象;每一个同事类对象在需要与其他同事通信的时候与它的中介者通信。
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
public class Mediator {
public static void main(String[] args) {
co1 c1 = new co1();
co2 c2 = new co2();
co3 c3 = new co3();
ConcreteZhongjie zj = new ConcreteZhongjie(c1,c3);
c1.sendMessage("你好",c2);//通信失败
c1.sendMessage("你好",c3);
}
}
abstract class Colleage{
protected String name;
protected Zhongjie zhongjie;
public abstract void sendMessage(String message,Colleage getc);
public abstract void getMessage(String message);
}
class co1 extends Colleage{
public co1(){
this.name = "A";
}
public void sendMessage(String message,Colleage getc){
System.out.println("发送方:"+name+ " " + message);
zhongjie.send(message,this,getc);
}
public void getMessage(String message){
System.out.println("接收方:"+name + " " + message);
}
}
class co2 extends Colleage{
public co2(){
this.name = "B";
}
public void sendMessage(String message,Colleage getc){
System.out.println("发送方:"+name+ " " + message);
zhongjie.send(message,this,getc);
}
public void getMessage(String message){
System.out.println("接收方:"+name + " " + message);
}
}
class co3 extends Colleage{
public co3(){
this.name = "C";
}
public void sendMessage(String message,Colleage getc){
System.out.println("发送方:"+name+ " " + message);
zhongjie.send(message,this,getc);
}
public void getMessage(String message){
System.out.println("接收方:"+name + " " + message);
}
}
abstract class Zhongjie{
public abstract void send(String message,Colleage sendc,Colleage getc);
}
class ConcreteZhongjie extends Zhongjie{
private List<Colleage> list = new ArrayList<>();
public ConcreteZhongjie(Colleage ...c){
for(Colleage cc : c){
cc.zhongjie = this;
list.add(cc);
}
}
@Override
public void send(String message,Colleage sendc,Colleage getc) {
if (list.contains(getc))
getc.getMessage(message);
else
System.out.println("通信失败");
}
}

适用于:

  • 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解
  • 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象
  • 想定制一个分布在多个类中的行为,而又不想生成太多的子类

6. 备忘录模式(Memento)

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

  • Memento(备忘录)存储原发器对象的内部状态,原发器根据需要决定备忘录存储原发器的哪些内部状态;防止原发器以外的其他对象访问备忘录。
  • Originator(原发器)创建一个备忘录,用于记录当前时刻它的内部状态;使用备忘录恢复内部状态。
  • Caretaker(管理者)负责保存好备忘录;不能对备忘录的内容进行操作或检查。
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
public class Memento {
public static void main(String[] args) {
Caretaker care = new Caretaker();
Originator orign = new Originator();
orign.setState("1024");
beiwang b1 = orign.CreateBeiwang();
orign.setState("2048");
beiwang b2 = orign.CreateBeiwang();
orign.setState("4096");
beiwang b3 = orign.CreateBeiwang();
care.Add(b1);
care.Add(b2);
care.Add(b3);
care.show();
orign.setState(care.get(2).getState());//恢复到第二次备份
}
}
class Originator{//原发器
private String state;
public void setState(String state){
this.state = state;
}
public String getState(){
return state;
}
public beiwang CreateBeiwang(){
return new beiwang(state);
}
public void setBeiwang(beiwang bei){
state = bei.getState();
}
}
class beiwang{//备忘录
private String state;
public beiwang(String state){
this.state = state;
}
public String getState(){
return state;
}
}
class Caretaker{
private List<beiwang> list = new ArrayList<>();
public void Add(beiwang b){
list.add(b);
}
public beiwang Get(int index){
return list.get(index-1);
}
public void show(){
int cnt = 1;
for(beiwang bb : list){
System.out.println("第"+cnt+"次备份:"+bb.getState());
cnt++;
}
}
}

适用于:

  • 必须保存一个对象在某一个时刻的状态,这样以后方便恢复
  • 如果一个用接口来让其他对象得到这些状态,将会暴露对象得实现细节并破坏对象的封装性

7. 观察者模式

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新

  • Subject(目标)知道它的观察者,可以有任意多个观察者观察同一个目标;提供注册和删除观察者对象的接口。

  • Observer(观察者)为那些在目标发生改变时需获得通知的对象定义一个接口.ConcreteSubject(具体目标)将有关状态存入各ConcreteObserver对象;当它的状态发生改变时,向它的各个观察者发出通知。

  • ConcreteObserver(具体观察者)维护一个指向ConcreteSubject对象的引用;存储有关状态,这些状态应与目标的状态保持一致;实现Observer的更新接口,以使自身状态与目标的状态保持一致。

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
public class Observer {
public static void main(String[] args) {
Subject subject1 = new ConcreteSubject();
guancha g1 = new user("kai",subject1);
guancha g2 = new user("rui",subject1);
guancha g3 = new user("xing",subject1);
guancha g4 = new user("wang",subject1);
subject1.Notify();
}
}
interface Subject{
public void Attach(guancha guan);
public void Detach(guancha guan);
public void Notify();
}
class ConcreteSubject implements Subject{
private List<guancha> list = new ArrayList<>();
@Override
public void Attach(guancha guan) {
list.add(guan);
}
@Override
public void Detach(guancha guan) {
list.remove(guan);
}
@Override
public void Notify() {
for(guancha gg : list){
gg.Update();
}
}
}
interface guancha{
public void Update();
}
class user implements guancha{
private Subject subject;
private String name;
public user(String name,Subject sub){
this.subject = sub;
this.name = name;
subject.Attach(this);
}
@Override
public void Update() {
System.out.println(name+" 收到通知");
}
}

该代码体现了基本思路,要求的状态一致可以自行更改

适用于:

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用
  • 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时
  • 当一个对象必须通知其他对象,而又不能假定其他对象是谁,即不希望这些对象是紧耦合的

分析:A-迭代器模式 B-中介者模式 C-备忘录模式

8. 状态模式

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

  • Context(上下文)定义客户感兴趣的接口;维护一个ConcreteState子类的实例,这个实例定义当前状态。
  • State(状态)定义一个接口以封装与Context的一个特定状态相关的行为。
  • ConcreteState(具体状态子类)每个子类实现与Context的一个状态相关的行为。
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
public class State {
public static void main(String[] args) throws InterruptedException {
Context con = new Context();
con.Request();
con.Request();
con.Request();
con.Request();
con.Request();
}
}
class Context{//贩卖机
private int count;
private zhuangtai state;
public Context(){
count = 3;
state = new StateA();
}
public int getCount() {
return count;
}
public zhuangtai getState() {
return state;
}
public void setCount(int count) {
this.count = count;
}
public void setState(zhuangtai state) {
this.state = state;
}
public void Request() throws InterruptedException {
state.Handle(this);
}
}
interface zhuangtai{
public void Handle(Context context) throws InterruptedException;
}
class StateA implements zhuangtai{
@Override
public void Handle(Context context) {
int count = context.getCount();
if (count-1>=1){
System.out.println("购买成功");
context.setCount(count-1);
}else{
System.out.println("购买成功");
context.setCount(count-1);
context.setState(new StateB());
}
}
}
class StateB implements zhuangtai{
@Override
public void Handle(Context context) throws InterruptedException {
System.out.println("补货中。。。。");
Thread.sleep(2000);
System.out.println("补货成功");
context.setCount(3);
context.setState(new StateA());
System.out.println("请重新购买");
}
}

适用于:

  • 一个对象的行为决定于它的状态,并且它必须在运行时根据状态改变它的行为
  • 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态,这个状态常用一个或多个枚举常量表示

9. 策略模式

意图:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换,此模式可以使算法独立于使用它们的客户而变化

  • Strategy(策略)定义所有支持的算法的公共接口。Context 使用这个接口来调用某
  • ConcreteStrategy定义的算法。
  • ConcreteStrategy(具体策略)以Strategy接口实现某具体算法。
  • Context(上下文)用一个ConcreteStrategy对象来配置;维护一个对Strategy 对象的引用;可定义一个接口来让Strategy 访问它的数据。
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 celue {
public static void main(String[] args) {
Strategy jia = new jia();
Context c = new Context(jia);
c.Operate(1,2);
}
}
class Context{
private Strategy strategy;

public Context(Strategy strategy){
this.strategy = strategy;
}
public void Operate(int a,int b){
strategy.suan(a,b);
}
}
interface Strategy{
public void suan(int a,int b);
}
class jia implements Strategy{
@Override
public void suan(int a, int b) {
System.out.println(a+b);
}
}
class jian implements Strategy{
@Override
public void suan(int a, int b) {
System.out.println(a-b);
}
}

适用于:

  • 许多相关的类仅仅是行为有异,“策略”提供了一种用多个行为中的一个行为来配置个类的方法
  • 需要使用一个算法的不同变体
  • 算法使用客户不应该知道的数据,可使用策略模式以避免暴露复杂的,与算法相关的数据结构
  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的Strategy类中,以替代这些条件语句

10. 模板方法

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

  • AbstractClass(抽象类)定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤;实现模板方法,定一个算法的骨架,该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作。
  • ConcreteClass(具体类)实现原语操作以完成算法中与特定子类相关的步骤。
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 class moban {
public static void main(String[] args) {
Student s1 = new Student();
Teacher t1 = new Teacher();
s1.Template();
t1.Template();
}
}
abstract class Person{
public void Template(){//同一个模板 存放共同步骤
System.out.println("去教室");
Primitive1();
System.out.println("出教室");
}
public abstract void Primitive1();//不同的具体步骤
}
class Student extends Person{
@Override
public void Primitive1() {
System.out.println("学习");
}
}
class Teacher extends Person{
@Override
public void Primitive1() {
System.out.println("讲课");
}
}

适用于:

  • 一次性实现算法的不变部分,并将可变的行为留给子类实现
  • 各子类中公共的行为应该提取出来并集中到一个公共父类中,避免代码重复

11. 访问者模式

意图:表示一个作用于某对象结构中的各元素的操作,它允许在不改变各元素的类前提下定义作用于这些元素的新操作

  • Visitor(访问者)为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送 Visit请求给该访问者的那个类,这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它
  • ConcreteVisitor (具体访问者)实现每个有Visitor声明的操作,每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。Element(元素)定义以一个访问者为参数的Accept操作。
  • ConcreteElement(具体元素)实现以一个访问者为参数的Accept操作。
  • ObjectStructure(对象结构)能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个组合或者一个集合,如一个列表或一个无序集合。
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
public class fangwenzhe {
public static void main(String[] args) {
PersonStructure ps = new PersonStructure();
visitor1 v1 = new visitor1();
ps.Accept(v1);
v1.show();
visitor2 v2 = new visitor2();
ps.Accept(v2);
v2.show();
}
}
interface Visitor{
public void visitStudent(Student student);
public void visitTeacher(Teacher teacher);
public void show();
}
class visitor1 implements Visitor{//分别统计学生和老师年龄总和
private int sumage1 = 0;
private int sumage2 = 0;
@Override
public void visitStudent(Student student) {
System.out.println("1:" + student.getName()+" "+student.getAge());
sumage1 += student.getAge();
}
@Override
public void visitTeacher(Teacher teacher) {
System.out.println("1:" + teacher.getName()+" "+teacher.getAge());
sumage2 += teacher.getAge();
}
public void show(){
System.out.println(sumage1+" "+sumage2);
}
}
class visitor2 implements Visitor{//最高成绩和最高工龄
private int maxscore = 0;
private int maxworkage = 0;
@Override
public void visitStudent(Student student) {
System.out.println("2:" + student.getName()+" "+student.getScore());
if (student.getScore()>maxscore){
maxscore = student.getScore();
}
}
@Override
public void visitTeacher(Teacher teacher) {
System.out.println("2:" + teacher.getName()+" "+teacher.getWorkyear());
if (teacher.getWorkyear()>maxworkage){
maxworkage = teacher.getWorkyear();
}
}
@Override
public void show() {
System.out.println(maxscore+" "+maxworkage);
}
}
class PersonStructure{
private List<Person> list = new ArrayList<>();
public PersonStructure(){
list.add(new Student("A",14,98));
list.add(new Student("B",15,99));
list.add(new Student("C",14,97));
list.add(new Teacher("周老师",46,20));
list.add(new Teacher("老王",35,15));
list.add(new Teacher("李云龙",40,18));
}
public void Accept(Visitor visitor){
for (Person pp : list){
pp.Accept(visitor);
}
}
}
abstract class Person{
public String getName() {
return name;
}
public int getAge() {
return age;
}
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public abstract void Accept(Visitor visitor);
}
class Student extends Person{
public int getScore() {
return score;
}
private int score;
public Student(String name,int age,int score){
super(name, age);
this.score = score;
}
@Override
public void Accept(Visitor visitor) {
visitor.visitStudent(this);
}
}
class Teacher extends Person{
public int getWorkyear() {
return workyear;
}
private int workyear;
public Teacher(String name,int age,int workyear){
super(name, age);
this.workyear = workyear;
}
@Override
public void Accept(Visitor visitor) {
visitor.visitTeacher(this);
}
}

适用于:

  • 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于其具体类的操作
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而又想避免操作污染这些对象的类,Visitor使得用户可以将相关的操作集中起来定义在一个类中,当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作
  • 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作,改变对象结构类需要重定义对所有访问者的接口,代价很大。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好

五. 简单练习

这一部分旨在学习完之后进行简单的复习

1.

答案:装饰器模式 享元模式 适配器模式

2.

答案:单例模式 组合模式 装饰器模式

3.

答案:DCAD

4.

答案:适配器模式 桥接模式

5.

答案:中介者模式 观察者模式

6.

答案:DAD

7.

答案:ADC


设计模式
http://kaikai12321.github.io/2023/01/20/设计模式/
作者
Hou Kai
发布于
2023年1月20日
许可协议