软件设计师设计模式
- [0 考试形式](#0 考试形式)
- [1 设计模式要素(X)](#1 设计模式要素(X))
- [2 创建型设计模式(5)](#2 创建型设计模式(5))
-
-
-
- [Simple Factory(简单工厂)](#Simple Factory(简单工厂))
- [1. Factory Method(工厂方法)](#1. Factory Method(工厂方法))
- [2. Abstract Factory(抽象工厂)](#2. Abstract Factory(抽象工厂))
- [3. Builder(生成器)](#3. Builder(生成器))
- [4. Prototype(原型)](#4. Prototype(原型))
- [5. Singleton(单例)](#5. Singleton(单例))
-
-
- [3 结构性设计模式(7)](#3 结构性设计模式(7))
-
-
-
- [1. Adapter(适配器)](#1. Adapter(适配器))
- [2. Bridge(桥接)](#2. Bridge(桥接))
- [3. Composite(组合)](#3. Composite(组合))
- [4. Decorator(装饰器)](#4. Decorator(装饰器))
- [5. Facade(外观)](#5. Facade(外观))
- [6. Flyweight(享元)](#6. Flyweight(享元))
- [7. Proxy(代理)](#7. Proxy(代理))
-
-
- [4 行为设计模式(11)](#4 行为设计模式(11))
-
-
-
- [1. Chain of Responsibility(责任链)](#1. Chain of Responsibility(责任链))
- [2. Command(命令)](#2. Command(命令))
- [3. Interpreter(解释器)](#3. Interpreter(解释器))
- [4. Iterator(迭代器)](#4. Iterator(迭代器))
- [5. Mediator(中介者)](#5. Mediator(中介者))
- [6. Memento(备忘录)](#6. Memento(备忘录))
- [7. Observer(观察者)](#7. Observer(观察者))
- [8. State(状态)](#8. State(状态))
- [9. Strategy(策略)](#9. Strategy(策略))
- [10. Template Method(模板方法)](#10. Template Method(模板方法))
- [11. Visitor(访问者)](#11. Visitor(访问者))
-
-
- [5 应用举例(X)](#5 应用举例(X))
0 考试形式
上午:设计模式的意图、设计模式对应什么类型、结构里面代码的作用、适用性
1 设计模式要素(X)
设计模式使得人们更加方便地复用成功的设计和体系结构
设计模式基本要素:模式名称、问题、解决方案、效果
创建型模式:与对象的创建有关
结构型模式:处理类或对象的组合
行为型模式:对类或对象怎样交互和怎样分配职责进行描述
下图必背!!英文和中文都要

速记:
工人(工厂)抽(抽象工厂)出原生(原型)单(单例)亲创建(创建型)新的家庭
创建对象:单原生抽(单元生抽,老好喝了)
结构对象:乔氏组装享受外带(的服务)
行为对象:迭责终观察备忘录状态,访问策略命令(爹折中地观察备忘录的状态,询问妻子该采用什么策略和命令命令)
关于public protected private的区别

2 创建型设计模式(5)
简单工厂模式------工厂方法模式------抽象工厂模式
个人理解
0、简单工厂:工厂类不抽象,直接创建工厂对象去生产,违反开放封闭。
1、工厂:工厂抽象,由其子类对象去生产,简单实现分离
2、抽象工厂:在工厂基础上,工厂和产品的生产关系不止1:1,而是可以组合生产。
不论是什么工厂,工厂:产品 最少是1:*
3、 生成器:相当于车间:产品 可以是 *:1。
要点1:产品的组成部分 (属性值)不在产品类中直接定义了,仅声明一些表示 方法,比如输出产品的组成部分。
要点2:产品的具体组成部分 由不同的车间决定并创建 。
要点3:不同的车间 都继承 与同一个生成器 ,该生成器内部声明 一个创建方法 ,所以不同车间继承该生成器时,
虽然重写的内容不一样,但是在实际声明车间对象时,由于向上转型 ,看起来都是用同样的构建过程。
所以总结:复杂对象 的构建与表示分离,使得同样的构建过程可以创建不同的表示。
4、原型:主要就是克隆自己
要点1:它的适用性第一点和抽象工厂的不同在于,它强调构成
要点2:既然要克隆,则要在子类继承时定义属性及构造方法(有参和无参),总之需要能改变其属性。这样在实例化对象时能够动态装载 。
要点3:既然能动态装载 ,就意味着想要不同属性值的产品,不需要单独再搞一个工厂类和实例化工厂对象。
要点4:当你要搞很多个相同属性值的对象时,克隆比重复声明方便的多。
5、单例:一个类永远只有一个静态实例
要点1:类中
Simple Factory(简单工厂)
-
简单工厂模式属创建型模式,但不属于23种设计模式之一。
-
定义:定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。在简单工厂模式中用于被创建实例的方法通常为静态(static)方法,因此简单工厂模式又被成为静态工厂方法
-
简单工厂模式违反了开放封闭原则,即对扩展开放对修改也开放。
javapublic class SimpleFactory { public static void main(String[] args) { Product productA = Factory.createProduct("A"); productA.info(); Product productB = Factory.createProduct("B"); productB.info(); } } class Factory{ public static Product createProduct(String type){ Product product =null; switch (type){ case "A": product = new ProductA(); break; case "B": product = new ProductB(); break; default: System.out.println("没有 " + type + " 类型的产品!"); return null; } return product; } } abstract class Product{ public abstract void info(); } class ProductA extends Product{ @Override public void info() { System.out.println("产品的信息:A"); } } class ProductB extends Product{ @Override public void info() { System.out.println("产品的信息:B"); } }
1. Factory Method(工厂方法)
-
意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
-
结构:创建型类模式
javapublic class FactoryMethod { public static void main(String[] args) { // 父类 对象名 = new 子类(); Factory factoryA = new FactoryA(); Product productA = factoryA.createProduct(); productA.info(); Factory factoryB = new FactoryB(); Product productB = factoryB.createProduct(); productB.info(); } } interface Factory{ Product createProduct(); } class FactoryA implements Factory{ @Override public Product createProduct() { return new ProductA(); } } class FactoryB implements Factory{ @Override public Product createProduct() { return new ProductB(); } } interface Product{ void info(); } class ProductA implements Product{ @Override public void info() { System.out.println("产品的信息:A"); } } class ProductB implements Product{ @Override public void info() { System.out.println("产品的信息:B"); } } -
适用性:Factory Method 模式适用于
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类 希望由它的子类来 指定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
2. Abstract Factory(抽象工厂)
- 意图
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。 - 结构:创建型对象模式

java
public class AbstractFactory {
public static void main(String[] args) {
Factory factory1 = new Factory1();
ProductA productA1 = factory1.createProductA();
productA1.info();
ProductB productB1 = factory1.createProductB();
productB1.info();
Factory factory2 = new Factory2();
ProductA productA2 = factory2.createProductA();
productA2.info();
ProductB productB2 = factory2.createProductB();
productB2.info();
}
}
// 声明一个创建抽象产品对象的操作接口
interface Factory{
ProductA createProductA();
ProductB createProductB();
}
// 实现创建具体产品对象的操作
class Factory1 implements Factory{
@Override
public ProductA createProductA() {
return new ProductA1();
}
@Override
public ProductB createProductB() {
return new ProductB1();
}
}
class Factory2 implements Factory{
@Override
public ProductA createProductA() {
return new ProductA2();
}
@Override
public ProductB createProductB() {
return new ProductB2();
}
}
// 为一类产品对象声明一个接口
interface ProductA{
void info();
}
interface ProductB{
void info();
}
// 定义一将被相应的具体工厂创建的产品对象
class ProductA1 implements ProductA{
@Override
public void info() {
System.out.println("产品的信息:A1");
}
}
class ProductA2 implements ProductA{
@Override
public void info() {
System.out.println("产品的信息:A2");
}
}
class ProductB1 implements ProductB{
@Override
public void info() {
System.out.println("产品的信息:B1");
}
}
class ProductB2 implements ProductB{
@Override
public void info() {
System.out.println("产品的信息:B2");
}
}
- 适用性:Abstract Factory 模式适用于
- 一个系统要独立于 它的产品的创建、组合和表示时。
- 一个系统要由多个产品系列中的一个来配置时。
- 当要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当提供一个产品类库,只想显示它们的接口而不是实现时。
- 积累
为图形用户界面(GUI)组件定义不同平台的并行类层次结构,适合采用抽象工厂模式
3. Builder(生成器)
-
意图
将一个复杂对象 的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 -
结构:创建型对象模式
javapublic class Main { public static void main(String[] args) { Director director = new Director(); Builder builder1 = new Builder1(); director.Construct(builder1); Product product1 = builder1.getResult(); product1.show(); Builder builder2 = new Builder2(); director.Construct(builder2); Product product2 = builder2.getResult(); product2.show(); } } class Director{ public void Construct(Builder builder){ builder.BuildPart(); } } abstract class Builder{ public abstract void BuildPart(); public abstract Product getResult(); } class Builder1 extends Builder{ Product product = new Product(); @Override public void BuildPart() { product.add("A"); product.add("B"); product.add("C"); product.add("D"); product.add("E"); product.add("F"); } @Override public Product getResult() { return product; } } class Builder2 extends Builder{ Product product = new Product(); @Override public void BuildPart() { product.add("A"); product.add("B"); product.add("C"); } @Override public Product getResult() { return product; } } class Product{ List<String> parts = new ArrayList<String>(); public void add(String part){ parts.add(part); } public void show(){ System.out.print("产品的组成:"); for (String part : parts) { System.out.print(part + " "); } System.out.println(); } } -
适用性:Builder 模式适用于
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
4. Prototype(原型)
-
意图
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。 -
结构:创建型对象模式
- Prototype声明一个复制自身的接口。
- ConcretePrototype 实现一个复制自身的操作。
- Client 让一个原型复制自身从而创建一个新的对象

javapublic class Main { public static void main(String[] args) { Product product1 = new Product(2022,5.28); System.out.println(product1.getId()+ " " + product1.getPrice()); Product product2 = (Product) product1.Chlone(); System.out.println(product2.getId()+ " " + product2.getPrice()); } } interface Prototype{ Object Chlone(); } class Product implements Prototype{ private int id; private double price; public Product(){} public Product(int id,double price){ this.id = id; this.price = price; } public int getId() { return id; } public double getPrice() { return price; } @Override public Object Clone() { Product object = new Product(); object.id = this.id; object.price = this.price; return object; } } -
适用性:Prototype 模式适用于
- 当一个系统应该独立于它的产品创建、构成和表示时。
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们,可能比每次用合适的状态手工实例化该类更方便一些。
5. Singleton(单例)
-
意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。 -
结构:创建型对象模式

其中:Singleton指定一个Instance操作,允许客户访问它的唯一实例,Instance是一个类
操作:可能负责创建它自己的唯一实例。javapublic class SingletonPattern { public static void main(String[] args) { Singleton instance1 = Singleton.getInstance(); Singleton instance2 = Singleton.getInstance(); Singleton instance3 = Singleton.getInstance(); System.out.println("instance1: " + instance1); System.out.println("instance2: " + instance2); System.out.println("instance3: "+ instance3); } } class Singleton{ private static Singleton instance = new Singleton(); private Singleton(){}; public static Singleton getInstance(){ return instance; } }
-
适用性
Singleton 模式适用于:- 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
- 当这个唯一实例应该是通过子类化可扩展的,并且客户无须更改代码就能使用一个扩展的实例时。
3 结构性设计模式(7)
个人理解:
1、适配器:Client需要将笔记本通过HDMI线扩展到VGA的屏幕上,但是此时两端的接口分别是HDMI和VGA,而视频线要么两头都是HDMI要么都是VGA,这时候就需要一个转换器。
要点1:用户现在有HDMI线(Adaptee),Target是VGA
要点2:Adapter将要被适配的Adaptee装入,即可完成Adaptee到Target接口的转换。
2、桥接:跟生成器模式有点像,但并不一样,先说桥接特点
要点1:主要目的是把抽象部分和实现部分分离,两个部分互相独立。
抽象的车(父类)1个,抽象的档(父类)1个,车型10个,档3种
假设完整的车=车型+档。那么在不考虑初始化的情况下 ,如果按照以前,抽象类要有两个属性(车型、档)。
那么就需要定义1+1+10*3个类
如果将两个属性(车型、档)分离,即抽象类的抽象部分(属性)、子类的实现部分(车型、档的具体值)分离。
那么只需要定义1+1+10+3个类
要点2:父类中有抽象方法Operation(),Operation()中调用被桥接类的实现方法。而生成器中,仍然是生成器实现,产品类表现。
3、组合:树形结构表示"部分-整体",使单个对象和组合对象的使用具有一致性。
要点1:Component是组合部分,组合部分包括Leaf和Composite,Composite是文件夹,文件夹中又能包括组合部分。
4、装饰器:能给对象动态添加职责,装饰器父类继承对象的父类,同时添加职责后的新对象覆盖旧对象。
5、外观:对外提供一个简单的界面给客户,对内能根据客户的选择调用不同的子系统
6、享元:与桥接的区别如下:
区别1:桥接重点在于分离同一个事物的抽象与具体实现,享元重点在于分离内在状态和外在状态。
内在状态是一成不变、可共享的,外部状态是可变的
区别2:桥接的抽象和实现分离是指------基础遥控器、高级遥控器、品牌------3个都可能有n个类
享元的分离是指 棋子(黑白)、位置 分离,只要把位置分离出去,类的数量完全固定
1. Adapter(适配器)
-
意图
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 -
结构

其中:- Target定义Client使用的与特定领域相关的接口。
- Client与符合Target接口的对象协同。
- Adaptee定义一个已经存在的接口,这个接口需要适配。
- Adapter对Adaptee的接口与Target接口进行适配。
javapublic class AdapterPattern { public static void main(String[] args) { Target target = new Adapter(); target.Request(); } } class Target{ public void Request(){ System.out.println("普通请求~"); } } class Adapter extends Target { private Adaptee adaptee = new Adaptee(); @Override public void Request() { adaptee.SpecificRequest(); } } class Adaptee{ public void SpecificRequest(){ System.out.println("特殊请求~"); } } -
适用性
Adapter 模式适用于:- 想使用一个已经存在的类,而它的接口不符合要求。
- 想创建一个可以服用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。(了解)
- (仅适用于对象Adapter)想使用一个已经存在的子类,但是不可能对每一个都进行子
类化以匹配它们的接口。对象适配器可以适配它的父类接口。(了解)
2. Bridge(桥接)
-
意图
将抽象部分与其实现部分分离,使它们都可以独立地变化。 -
结构
javapublic class BridgePattern { public static void main(String[] args) { Product productA = new ProductA(); Product productB = new ProductA(); Color red = new Red(); productA.setName("产品A"); productA.setColor(red); productA.Operation(); Blue blue = new Blue(); productB.setName("产品B"); productB.setColor(blue); productB.Operation(); } } abstract class Product{ private String name; protected Color color; public void setName(String name){ this.name = name; } public String getName(){ return name; } public void setColor(Color color){ this.color = color; } public abstract void Operation(); } interface Color{ void OperationImpl(String name); } class ProductA extends Product{ @Override public void Operation() { color.OperationImpl(this.getName()); } } class Red implements Color{ @Override public void OperationImpl(String name) { System.out.println(name + ": 红色" ); } } class Blue implements Color{ @Override public void OperationImpl(String name) { System.out.println(name + ": 蓝色" ); } } -
适用性(了解)
- 不希望在抽象和它的实现部分之间有一个固定的绑定关系。
- 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。
- 对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译。
- 有许多类要生成的类层次结构。
- 想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。
3. Composite(组合)
-
意图
将对象组合成树型结构 以表示**"部分-整体"的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性**。
-
结构

其中:
- Component 为组合中的对像声明接口:在适当情况下实现所有类共有接口的默认行为:声明一个接口用于访问和管理 Component 的子组件;(可选)在递归结构中定义一个接口,用于访问一个父组件,并在合适的情况下实现它。
- Leaf 在组合中表示叶结点对象,叶结点没有子结点;在组合中定义图元对象的行为。
- Composite定义有子组件的那些组件的行为;存储子组件;在Component接口中实现与子组件有关的操作。
- Client 通过 Component 接口操纵组合组件的对象。
javaimport java.util.*; public class CompositePattern { public static void main(String[] args) { // 父类名 对象名 = new 子类名(); AbstractFile root = new Folder("root"); AbstractFile folderA = new Folder("folderA"); AbstractFile folderB = new Folder("folderB"); AbstractFile fileC = new File("fileC"); AbstractFile fileD = new File("fileD"); AbstractFile fileE = new File("fileE"); root.Add(folderA); root.Add(folderB); root.Add(fileC); folderA.Add(fileD); folderA.Add(fileE); print(root); } static void print(AbstractFile file){ file.printName(); List<AbstractFile> childrenList = file.getChildren(); if (childrenList == null){ return; } for (AbstractFile children : childrenList) { print(children); } } } abstract class AbstractFile{ protected String name; public void printName(){ System.out.println(name); } public abstract boolean Add(AbstractFile file); public abstract boolean Remove(AbstractFile file); public abstract List<AbstractFile> getChildren(); } class Folder extends AbstractFile { private List<AbstractFile> childrenList = new ArrayList<>(); public Folder(String name) { this.name = name; } @Override public boolean Add(AbstractFile file) { return childrenList.add(file); } @Override public boolean Remove(AbstractFile file) { return childrenList.remove(file); } @Override public List<AbstractFile> getChildren() { return childrenList; } } class File extends AbstractFile{ public File(String name) { this.name = name; } @Override public boolean Add(AbstractFile filei) { return false; } @Override public boolean Remove(AbstractFile file) { return false; } @Override public List<AbstractFile> getChildren() { return null; } } -
适用性
Composite 模式下适用于:
- 想表示对象的部分-整体层次结构。
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
4. Decorator(装饰器)
-
意图
动态地给一个对象添加一些额外的职责。就增加功能而言,Decorator模式比生成子类更加灵活。 -
结构

其中:- Component定义一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent定义一个对象,可以给这个对象添加一些职责。
- Decorator 维持一个指向 Component 对象的指针,并定义一个与Component 接口一致的接口。
- ConcreteDecorator 向组件添加职责。
javapublic class DecoratorPattern { public static void main(String[] args) { Person zhangsan = new Student("张三"); zhangsan = new DecoratorA(zhangsan); zhangsan = new DecoratorB(zhangsan); zhangsan.Operation(); System.out.println("==========分割线=============="); // 对像链 Person lisi = new DecoratorB(new DecoratorA(new Student("李四"))); lisi.Operation(); } } 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("考试~"); } } abstract class Person{ 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(name + "的职责:学习~"); } } -
适用性
Decorator 模式适用于:- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤销的职责。
- 当不能采用生成子类的方式进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是,由于类定义被隐藏,或类定义不能用于生成子类。(了解)
5. Facade(外观)
- 意图
为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 - 结构

其中:
- Facade知道哪些子系统类负责处理请求;将客户的请求代理给适当的子系统对象。
- Subsystem classes实现子系统的功能;处理有Facade对象指派的任务;没有Facade的任何相关信息,即没有指向Facade的指针。
java
import java.util.Scanner;
public class FacadePattern {
public static void main(String[] args) {
Facade facade = new Facade();
facade.methodA();
facade.methodB();
facade.methodC();
}
}
class Facade{
SubSystemOne subSystemOne;
SubSystemTwo subSystemTwo;
SubSystemThree subSystemThree;
public Facade(){
subSystemOne = new SubSystemOne();
subSystemTwo = new SubSystemTwo();
subSystemThree = new SubSystemThree();
}
public void methodA(){
subSystemOne.methodOne();
}
public void methodB(){
subSystemTwo.methodTwo();
}
public void methodC(){
subSystemThree.methodThree();
}
}
class SubSystemOne{
public void methodOne(){
System.out.println("执行子系统一的功能~");
}
}
class SubSystemTwo{
public void methodTwo(){
System.out.println("执行子系统二的功能~");
}
}
class SubSystemThree{
public void methodThree(){
System.out.println("执行子系统三的功能~");
}
}
- 适用性
Facade 模式适用于:- 要为一个复杂子系统提供一个简单接口时。
- 客户程序与抽象类的实现部分之间存在着很大的依赖性。
- 当需要构建一个层次结构的子系统时,使用 Facade 模式定义子系统中每层的入口点。
6. Flyweight(享元)
-
意图
运用共享技术有效地支持大量细粒度的对象。
-
结构

其中:
-
Flyweight 描述一个接口,通过这个接口 Flyweight 可以接受并作用于外部状态。
-
ConcreteFlyweight 实现Flyweight接口,并为内部状态(如果有)增加存储空间。
-
ConcreteFlyweight 对象必须是可共享的。它所存储的状态必须是内部的,即它必须独立于 ConcreteFlyweight 对象的场景。
-
并非所有的 Flyweight 子类都需要被共享。Flyweight 接口使共享成为可能,但它并不强制共享。在 Flyweight 对象结构的某些层次,UnsharedConcreteFlyweight 对象通常将ConcreteFlyweight 对象作为子结点。
-
FlyweightFactory 创建并管理Flyweight对象;确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory 对象提供一个已创建的实例或者在不存在时创建个实例。
-
Client 维持一个对 Flyweight 的引用;计算或存储一个或多个 Flyweight 的外部状态。
java/** * 享元模式 案例1 */ public class FlyweightPattern { public static void main(String[] args) { PieceFactory factory = new PieceFactory(); Piece whitePiece1 = factory.getPiece(0); whitePiece1.draw(66,87); System.out.println(whitePiece1); Piece blackPiece1 = factory.getPiece(1); blackPiece1.draw(20,11); System.out.println(blackPiece1); Piece whitePiece2 = factory.getPiece(0); whitePiece1.draw(26, 54); System.out.println(whitePiece2); Piece blackPiece2 = factory.getPiece(1); blackPiece2.draw(12, 34); System.out.println(blackPiece2); } } class PieceFactory{ private Piece[] pieces = {new WhitePiece(),new BlackPiece()}; public Piece getPiece(int key){ if (key == 0) return pieces[0]; else return pieces[1]; } } abstract class Piece{ protected String color; public abstract void draw(int x,int y); } class WhitePiece extends Piece{ public WhitePiece(){ this.color = "white"; } @Override public void draw(int x, int y) { System.out.println("draw a color: "+color + " piece x: " + x + " y: " + y); } } class BlackPiece extends Piece{ public BlackPiece(){ this.color = "black"; } @Override public void draw(int x, int y) { System.out.println("draw a color: " + color + " piece x: " + x + " y: " + y); } }java/** * 享元模式 案例2 */ public class FlyweightPattern { public static void main(String[] args) { ShapeFactory factory = new ShapeFactory(); Random random = new Random(); String[] colors = {"red","blue","green","whilte","black"}; for (int i = 1; i <= 10; i++) { int x = random.nextInt(colors.length); Shape shape = factory.getShape(colors[x]); System.out.print("第" + i + "个圆:"); shape.draw(random.nextInt(2022),random.nextInt(528)); } } } class ShapeFactory{ private Map<String,Shape> map = new HashMap<>(); public Shape getShape(String key){ if (!map.containsKey(key)) { map.put(key, new Circle(key)); System.out.println("create color: " + key + " circle"); } return map.get(key); } } abstract class Shape { protected String color; public abstract void draw(int x, int y); } class Circle extends Shape { public Circle(String color){ this.color = color; } @Override public void draw(int x, int y) { System.out.println("draw a color: " + color + " circle x:"+ x + " y:" + y); } } -
-
适用性
Flyweight模式适用于:
- 一个应用程序使用了大量的对象。
- 完全由于使用大量的对象,造成很大的存储开销。
- 对象的大多数状态都可变为外部状态。
- 如果删除 对象的外部状态 ,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,所以对于概念上明显有别的对象,标识测试将返回真值。
7. Proxy(代理)
- 意图
为其他对象提供一种代理以控制对这个对象的访问 - 结构

java
public class ProxyPattern {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
proxy.buy();
}
}
interface Subject{
void buy();
}
class Proxy implements Subject{
protected RealSubject realSubject;
public Proxy(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("付钱~");
}
}
- 适用性 (了解)
Poxy模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候,常见情况有:- 远程代理(Remote Proxy)为一个对象在不同地址空间提供局部代表。
- 虚代理(Virtual Proxy)根据需要创建开销很大的对象。
- 保护代理(Protection Proxy)控制对原始对象的访问,用于对象应该有不同的访问权限的时候。
- 智能引用(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。
4 行为设计模式(11)
个人理解:
2、命令:把遥控器(Invoker)与命令(Command)分开,对电视机(Receiver)进行请求,这样的好处是,假如客户对其他电器有同样的需求,如开机关机,那么命令就能复用。
1. Chain of Responsibility(责任链)
- 意图
使多个对象都有机会处理请求 ,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 - 结构

其中:- Handler定义一个处理请求的接口;(可选)实现后继链。
- ConcreteHandler处理它所负责的请求;可访问它的后继者;如果可处理该请求,就处理它,否则将该请求转发给后继者。
- Client向链上的具体处理者(ConcreteHandler)对象提交请求。
java
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
Handler counsellor = new Counsellor();
Handler dean = new Dean();
Handler headmaster= new Headmaster();
counsellor.setNext(dean);
dean.setNext(headmaster);
counsellor.HandRequest(25);
}
}
abstract class Handler{
protected Handler next;
public void setNext(Handler next){
this.next =next;
}
public abstract void HandRequest(int request);
}
class Counsellor extends Handler{
@Override
public void HandRequest(int request) {
if (request <= 7){
System.out.println("辅导员审批通过~");
}else {
if (next != null){
next.HandRequest(request);
}else {
System.out.println("无法审批");
}
}
}
}
class Dean extends Handler{
@Override
public void HandRequest(int request) {
if (request <= 15){
System.out.println("院长审批通过~");
}else {
if (next != null){
next.HandRequest(request);
}else {
System.out.println("无法审批");
}
}
}
}
class Headmaster extends Handler{
@Override
public void HandRequest(int request) {
if (request <= 30){
System.out.println("校长审批通过~");
}else {
if (next != null){
next.HandRequest(request);
}else {
System.out.println("无法审批");
}
}
}
}
- 适用性
Chain of Responsibility 模式适用于以下条件:- 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
- 想在不明确指定接收者的情况下 向多个对象中的一个提交一个请求。
- 可处理一个请求的对象集合应被动态指定。
2. Command(命令)
-
意图
将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化 ;对请求排队 或记录请求日志 ,以及支持可撤销的操作。
-
结构

其中:
- Command声明执行操作的接口。
- ConcreteCommand 将一个接收者对象绑定于一个动作:调用接收者相应的操作,以实现Execute。
- Client 创建一个具体命令对象并设定它的接收者。
- Invoker 要求该命令执行这个请求。
- Receiver 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
java
public class CommandPattern {
public static void main(String[] args) {
Tv tv = new Tv(); // 接收者 对象 电视机
Command onCommand = new OnCommand(tv); // 命令对象 开机命令
Command offCommand = new OnCommand(tv); // 命令对象 关机命令
Invoker invoker = new Invoker(); //请求者
invoker.setCommand(onCommand); // 给请求者设置 开机 命令
invoker.call(); // 请求者去请求命令
System.out.println("==============分割线===============");
invoker.setCommand(offCommand); // 给请求者设置 关机命令
invoker.call(); // 请求者去请求命令
}
}
class Invoker{ // 请求者
private Command command; // 命令
public void setCommand(Command command){ // 设置请求者的命令
this.command = command;
}
public void call(){ // 调用
command.Execute();
}
}
interface Command{ // 命令接口
void Execute(); // 执行命令
}
class OnCommand implements Command{// 开机命令
private Tv tv;
public OnCommand(Tv tv){
this.tv = tv;
}
@Override
public void Execute() {
tv.OnAction();
}
}
class OffCommand implements Command{ // 关机命令
private Tv tv;
public OffCommand(Tv tv){
this.tv = tv;
}
@Override
public void Execute() {
tv.OffAction();
}
}
class Tv{
public void OnAction(){ // 开机行为
System.out.println("电视机开机了...");
}
public void OffAction(){ // 关机行为
System.out.println("电视机关机了...");
}
}
- 适用性
Command 模式适用于:- 抽象出待执行的动作以参数化某对象。
- 在不同的时刻指定、排列和执行请求。
- 支持取消操作。
- 支持修改日志。
- 用构建在原语操作上的高层操作构造一个系统。
3. Interpreter(解释器)
- 意图
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 - 结构

java
public class InterpreterPattern {
public static void main(String[] args) {
Context context = new Context();
context.check("A区的开发人员");
context.check("B区的调试人员");
context.check("C区的测试人员");
System.out.println("========分割线=============");
context.check("D区的程序员");
context.check("D区的测试员");
context.check("C区的程序员");
}
}
class Context{
private String[] regions = {"A区","B区","C区"};
private String[] persions = {"开发人员","测试人员","调试人员"};
private NonterminalExpression nonterminal;
public Context(){
TerminalExpression region = new TerminalExpression(regions);
TerminalExpression person = new TerminalExpression(persions);
nonterminal = new NonterminalExpression(region,person);
}
public void check(String info){
boolean result = nonterminal.Interpret(info);
if (result){
System.out.println("识别成功~");
}else {
System.out.println("识别失败~");
}
}
}
interface Expression{
boolean Interpret(String 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("的");
// B区鹅调试人员 --> str = {"B区","调试人员"};
return region.Interpret(str[0]) && person.Interpret(str[1]);
}
}
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);
}
}
- 适用性
Interpreter模式适用于当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时 ,以下情况效果最好:- 该文法简单。对于复杂的发文,文法的类层次变得庞大而无法管理。
- 效率不是一个关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。
4. Iterator(迭代器)
- 意图
提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。 - 结构

其中:
- Iterator (迭代器)定义访问和遍历元素的接口。
- ConcreteIterator(具体迭代器)实现迭代器接口;对该聚合遍历时跟踪当前位置。
- Aggregate( 聚合)定义创建相应迭代器对象的接口。
- ConcreteAggregate (具体聚合)实现创建相应迭代器的接口,该操作返回 ConcreteIterator的一个适当的实例。
java
public class IteratorPattern {
public static void main(String[] args) {
BookAggregate bookAggregate = new BookAggregate();
String[] books = {"数据结构","操作系统","计算机网络","计算机组成原理"};
double[] prices = {10.24,20.48,40.96,81.92};
for (int i = 0; i < 4; i++) {
bookAggregate.Add(new Book(books[i],prices[i]));
}
Iterator iterator = bookAggregate.CreateIterator();
while (iterator.hasNext()) {
Book book = (Book) iterator.next();
System.out.println("书名:" + book.getName() + " 价格:" + book.getPrice());
}
}
}
interface Iterator{
boolean hasNext();
Object next();
}
class BookIterator implements Iterator{
private int index;
private BookAggregate bookAggregate;
public BookIterator(BookAggregate bookAggregate){
this.index = 0;
this.bookAggregate = bookAggregate;
}
@Override
public boolean hasNext() {
if (index < bookAggregate.getSize()){
return true;
}
return false;
}
@Override
public Object next() {
Object obj = bookAggregate.get(index);
index ++ ;
return obj;
}
}
class BookAggregate implements Aggregate{
private List<Book> list = new ArrayList<>();
public void Add(Book book){
list.add(book);
}
public Book get(int index){
return list.get(index);
}
public int getSize(){
return list.size();
}
@Override
public Iterator CreateIterator() {
return new BookIterator(this);
}
}
interface Aggregate{
Iterator CreateIterator();
}
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;
}
}
- 适用性
Iterator 模式适用于:- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 支持对聚合对象的多种遍历。
- 为遍历不同的聚合结构提供一个统一的接口。
5. Mediator(中介者)
- 意图
用一个中介对象来封装一系列的对象交互 。中介者使各对象不需要显式的相互引用 ,从而使其耦合松散,而且可以独立地改变它们之间的交互。 - 结构

其中:
-
Mediator (中介者)定义一个接口用于各同事(Colleague)对象通信。
-
ConcreteMediator (具体中介者)通过协调各同事对象实现协作行为;了解并维护它的各个同事。
-
Colleague class (同事类)知道它的中介者对象;每一个同事类对象在需要与其他同事通信的时候与它的中介者通信。
java
public class MediatorPattern {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
Colleague1 colleague1 =new Colleague1(mediator);
Colleague2 colleague2 = new Colleague2(mediator);
mediator.setColleague1(colleague1);
mediator.setColleague2(colleague2);
colleague1.sendMessage("软考加油~");
colleague2.sendMessage("祝你上岸~");
}
}
abstract class Colleague{
protected Mediator mediator;
}
class Colleague1 extends Colleague{
public Colleague1(Mediator mediator){
this.mediator = mediator;
}
public void sendMessage(String message){
mediator.sendMessage(message,this);
}
public void Notify(String message){
System.out.println("同事1收到消息:" + message);
}
}
class Colleague2 extends Colleague{
public Colleague2(Mediator mediator){
this.mediator = mediator;
}
public void sendMessage(String message){
mediator.sendMessage(message,this);
}
public void Notify(String message){
System.out.println("同事2收到消息:" + message);
}
}
abstract class Mediator{
public abstract void sendMessage(String message,Colleague colleague);
}
class ConcreteMediator extends Mediator{
private Colleague1 colleague1;
private Colleague2 colleague2;
public void setColleague1(Colleague1 colleague1){
this.colleague1 = colleague1;
}
public void setColleague2(Colleague2 colleague2){
this.colleague2 = colleague2;
}
@Override
public void sendMessage(String message, Colleague colleague) {
if (colleague == colleague1){
// 让同事2收到消息
colleague2.Notify(message);
}else {
// 让同事1收到消息
colleague1.Notify(message);
}
}
}
- 适用性
Mediator 模式适用于:- 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
- 一个对象引用其他很多对象 并且直接与这些对象通信,导致难以复用该对象。
- 想定制一个分布在多个类中的行为,而又不想生成太多的子类。
6. Memento(备忘录)
- 意图
在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。 - 结构

java
public class MementoPattern {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
Originator originator = new Originator();
originator.setState("1024");
Memento backup1 = originator.createMemento();
caretaker.addMemento(backup1);
originator.setState("2048");
Memento backup2 = originator.createMemento();
caretaker.addMemento(backup2);
originator.setState("4096");
Memento backup3 = originator.createMemento();
caretaker.addMemento(backup3);
System.out.println(originator.getState());
caretaker.showMemento();
Memento memento1 = caretaker.getMemento(2);
originator.setState(memento1.getState());
System.out.println("根据第2次备份还原之后的状态为:" + originator.getState());
}
}
class Originator{ // 原发器
private String state;
public void setState(String state){
this.state = state;
}
public String getState(){
return state;
}
public Memento createMemento(){
return new Memento(state);
}
public void setMemento(Memento memento){
state = memento.getState();
}
}
class Memento{ // 备忘录
private String state;
public String getState(){
return state;
}
public Memento(String state){
this.state = state;
}
}
class Caretaker{ // 管理者
private List<Memento> mementoList = new ArrayList<>();
public void addMemento(Memento memento){
mementoList.add(memento);
}
public Memento getMemento(int index){
// 判断参数是否合法
if (index >=1 && index <= mementoList.size()) {
return mementoList.get(index - 1);
}
return null;
}
public void showMemento(){
int cnt = 1;
for (Memento memento : mementoList) {
System.out.println("第" + cnt + "次备份,状态为:" + memento.getState());
cnt ++;
}
}
}
- 适用性
Mement 模式适用于:- 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
- 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
7. Observer(观察者)
- 意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 - 结构

其中:
- Subject(目标)知道它的观察者,可以有任意多个观察者观察同一个目标;提供注册和删除观察者对象的接口。
- Observer(观察者)为那些在目标发生改变时需获得通知的对象定义一个更新接口。
- ConcreteSubject(具体目标)将有关状态存入各ConcreteObserver对象;当它的状态发生改变时,向它的各个观察者发出通知。
- ConcreteObserver (具体观察者)维护一个指向 ConcreteSubject 对象的引用;存储有关状态,这些状态应与目标的状态保持一致
- 实现 Observer 的更新接口,以使自身状态与目标的状态保持一致。
java
public class ObserverPattern {
public static void main(String[] args) {
Subject subjectA = new ConcreteSubject("目标A");
Observer observerB = new ConcreteObserver("张三",subjectA);
Observer observerC = new ConcreteObserver("李四",subjectA);
Observer observerD = new ConcreteObserver("王五",subjectA);
subjectA.setState("更新了");
}
}
interface Subject { // 目标接口
void Attach(Observer observer); // 添加观察者
void Detach(Observer observer); // 删除观察者
void Notify(); // 状态改变后,通知所有观察者
void setState(String state); // 设置状态(改变状态)
String getState(); // 获取状态
}
class ConcreteSubject implements Subject {
private String name;
private String state;
private List<Observer> observerList;
public ConcreteSubject(String name) {
state = "未更新";
this.name = name;
observerList = new ArrayList<>();
}
@Override
public void Attach(Observer observer) {
observerList.add(observer);
}
@Override
public void Detach(Observer observer) {
observerList.remove(observer);
}
@Override
public void Notify() {
for (Observer observer : observerList) {
observer.update();
}
}
@Override
public void setState(String state) {
this.state = state;
System.out.println(name + "的状态发生变化,变化后的状态为:" + state);
Notify();
}
@Override
public String getState() {
return state;
}
}
interface Observer { // 观察者接口
void update(); // 收到通知,更新观察者的状态
}
class ConcreteObserver implements Observer {
private String name;
private String state;
private Subject subject;
public ConcreteObserver(String name, Subject subject) {
this.name = name;
this.subject = subject;
subject.Attach(this);
state = subject.getState();
}
@Override
public void update() {
System.out.println(name + " 收到通知");
state = subject.getState(); // 让当前观察者的状态 和 目标改变后的状态保持一致
System.out.println(name + " 改变后的状态为:"+state);
}
}
- 适用性
Observer 模式适用于:- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当对一个对象的改变需要同时改变其他对象 ,而不知道具体有多少对象有待改变时。
- 当一个对象必须通知其他对象,而它又不能假定其他对象是谁,即不希望这些对象是紧耦合的。
8. State(状态)
- 意图
允许一个对象在其内部状态改变时改变它的行为 。对象看起来似乎修改了它的类。
个人理解:一个对象(售货机)在类中定义的方法一般只有售卖,也就是只有固定的一种行为,但是没货时,在状态A中去把实例化对象的状态改为B,导致行为发生变化,所以看似修改了类。 - 结构

java
public class StatePattern {
public static void main(String[] args) {
Context context = new Context(); // count = 3
System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());
context.Request(); // 购买一个饮料 count = 2
context.Request(); // 购买一个饮料 count = 1
context.Request(); // 购买一个饮料 count = 0
System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());
context.Request(); // 无货,等待补货
System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());
context.Request(); // 购买一个饮料 count = 4
System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());
}
}
class Context{ // 贩卖机
private int count;
private State state;
public Context(){
count = 3;
state = new StateA();
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void Request(){ // 购买饮料
state.Handle(this);
}
}
interface State{
void Handle(Context context);
}
class StateA implements State{
@Override
public void Handle(Context context) {
int count = context.getCount();
if (count >= 1){
System.out.println("购买成功~");
context.setCount(count - 1);
if (context.getCount() == 0){
context.setState(new StateB()); // 设置为无货状态
}
}else {
System.out.println("购买失败~");
}
}
}
class StateB implements State{
@Override
public void Handle(Context context) {
int count = context.getCount();
if (count == 0){
System.out.println("购买失败!等待补货~");
context.setCount(5);
System.out.println("补货成功,请重新购买~");
context.setState(new StateA());
}
}
}
- 适用性
State 模式适用于:- 一个对象的行为决定于它的状态 ,并且它必须在运行时刻根据状态改变它的行为。
- 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚举常量表示。
9. Strategy(策略)
- 意图
定义 一系列的算法 ,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。
个人理解:注意,策略模式顾名思义,就是把一件事情发生的必要条件定义为策略抽象类,具体可以有很多子类策略实现,不止可以替换,还能扩充。【2014年上半年下午题试题三】 - 结构

java
public class StrategyPattern {
public static void main(String[] args) {
OperationContext context = new OperationContext(new Addstrategy());
context.Operation(20,17);
context = new OperationContext(new Substrategy());
context.Operation(20,17);
context = new OperationContext(new Multstrategy());
context.Operation(20,17);
}
}
class OperationContext{
private Strategy strategy;
public OperationContext(Strategy strategy){
this.strategy =strategy;
}
public void Operation(int a, int b){
strategy.TwoNumberOperation(a,b);
}
}
interface Strategy{
void TwoNumberOperation(int a,int b);
}
class Addstrategy implements Strategy{
@Override
public void TwoNumberOperation(int a, int b) {
System.out.println(a + b);
}
}
class Substrategy implements Strategy{
@Override
public void TwoNumberOperation(int a, int b) {
System.out.println(a - b);
}
}
class Multstrategy implements Strategy{
@Override
public void TwoNumberOperation(int a, int b) {
System.out.println(a * b);
}
}
- 适用性
Strategy 模式适用于:- 许多相关的类仅仅是行为有异。
- 需要使用一个算法的不同变体。
- 使用算法的客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的 Strategy 类中,以代替这些条 件语句。
10. Template Method(模板方法)
- 意图
定义 一个操作中的算法骨架 ,而将一些步骤延迟到子类中 。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
个人理解:所谓模板方法就是,抽象类中定义了公共方法的固定部分(骨架),剩余的可变部分由子类实现。 - 结构

其中:
- AbstractClass(抽象类)定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤;实现模板方法,定一个算法的骨架,该模板方法不仅调用原语操作,也调用定义在 AbstractClass 或其他对象中的操作。
- ConcreteClass(具体类)实现原语操作以完成算法中与特定子类相关的步骤。
java
public class TemplateMethodPattern {
public static void main(String[] args) {
// 父类名 对象名 = new 子类名();
Person student = new Student();
Person teacher = new Teacher();
student.TemplateMethod();
System.out.println("=========分割线=============");
teacher.TemplateMethod();
}
}
abstract class Person{
public void TemplateMethod(){
System.out.println("上课 去教室");
PrimitiveOperation1();
System.out.println("下课 离开教室");
PrimitiveOperation2();
}
public abstract void PrimitiveOperation1(); // 原语操作 1:上课过程 学生 听课... 老师 讲课
public abstract void PrimitiveOperation2(); // 原语操作 2:作业 学生 写作业 提交作业... 老师批改作业 打分数
}
class Student extends Person{
@Override
public void PrimitiveOperation1() {
System.out.println("学生:听课 学习 做笔记 提出问题");
}
@Override
public void PrimitiveOperation2() {
System.out.println("学生:写作业 提交作业");
}
}
class Teacher extends Person{
@Override
public void PrimitiveOperation1() {
System.out.println("老师:上课 讲课 解答问题 布置作业");
}
@Override
public void PrimitiveOperation2() {
System.out.println("老师:批改作业 打分数");
}
}
- 适用性
Template Method 模式适用于:- 一次性实现一个算法的不变的部分 ,并将可变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中 ,以避免代码重复。
- 控制子类扩展:模板方法在特定点调用"hook"操作(默认行为,子类可以在必要时进行重定义扩展),这就只允许在这些点进行扩展。
11. Visitor(访问者)
- 意图
表示一个作用于某对象结构中的各元素的操作 。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。 - 结构

其中:
- Visitor(访问者)为该对象结构中 ConcreteElement 的每一个类声明一个 Visit 操作。该操作的名字和特征标识了发送 Vist 请求给该访问者的那个类,这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
- ConcreteVisitor (具体访问者)实现每个有 Visitor 声明的操作,每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。Concrete Visitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
- Element (元素)定义以一个访问者为参数的 Accept 操作。
- ConcreteElement (具体元素)实现以一个访问者为参数的 Accept 操作。
- ObjectStructure (对象结构)能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个组合或者一个集合,如一个列表或一个无序集合。
java
public class VisitorPattern {
public static void main(String[] args) {
PersonStructure structure = new PersonStructure();
Visitor1 visitor1 = new Visitor1();
System.out.println("访问者1的访问记录:");
structure.Accept(visitor1);
System.out.println("学生年龄的总和:" + visitor1.getStudentAgeSum() +" 老师年龄的总和:" + visitor1.getTeacherAgeSUm());
System.out.println("=========分割线==============");
Visitor2 visitor2 = new Visitor2();
System.out.println("访问者2的访问记录:");
structure.Accept(visitor2);
System.out.println("学生的最高成绩:" + visitor2.getMaxScore() + " 老师的最高工龄:" + visitor2.getMaxWorkYear());
}
}
interface Visitor{
void VistStudent(Student student); // 访问
void vistTeacher(Teacher teacher); // 访问老师
}
class Visitor1 implements Visitor{ // 访问者1 分别统计学生和老师的年龄总和
private int studentAgeSum = 0;
private int teacherAgeSUm =0;
public int getStudentAgeSum() {
return studentAgeSum;
}
public int getTeacherAgeSUm() {
return teacherAgeSUm;
}
@Override
public void VistStudent(Student student) {
System.out.println("访问者1访问学生:" + student.getName() + " 年龄:" + student.getAge());
studentAgeSum += student.getAge();
}
@Override
public void vistTeacher(Teacher teacher) {
System.out.println("访问者1访问老师:" + teacher.getName() + " 年龄:" + teacher.getAge());
teacherAgeSUm += teacher.getAge();
}
}
class Visitor2 implements Visitor{ // 访问者2 分别求出 学生的最高成绩 以及 老师的最高工龄
private int maxScore = -1;
private int maxWorkYear = -1;
public int getMaxScore() {
return maxScore;
}
public int getMaxWorkYear() {
return maxWorkYear;
}
@Override
public void VistStudent(Student student) {
System.out.println("访问者2访问学生:" + student.getName() + " 成绩:" + student.getScore());
maxScore = Math.max(maxScore,student.getScore());
}
@Override
public void vistTeacher(Teacher teacher) {
System.out.println("访问者2访问老师:" + teacher.getName() + " 工龄:" + teacher.getWorkYear());
maxWorkYear = Math.max(maxWorkYear,teacher.getWorkYear());
}
}
class PersonStructure{
private List<Person> personList = new ArrayList<>();
public PersonStructure(){
personList.add(new Student("张三",20,70));
personList.add(new Student("李四",21,80));
personList.add(new Student("王五",22,90));
personList.add(new Teacher("李老师",26,3));
personList.add(new Teacher("陈老师",27,4));
personList.add(new Teacher("刘老师",28,5));
}
public void Accept(Visitor visitor){
for (Person person : personList) {
person.Accept(visitor);
}
}
}
abstract class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge() {
return age;
}
public abstract void Accept(Visitor visitor);
}
class Student extends Person{
private int score;
public Student(String name,int age,int score){
super(name,age);
this.score = score;
}
public int getScore(){
return score;
}
@Override
public void Accept(Visitor visitor) {
visitor.VistStudent(this);
}
}
class Teacher extends Person{
private int workYear;
public Teacher(String name,int age,int workYear){
super(name,age);
this.workYear = workYear;
}
public int getWorkYear(){
return workYear;
}
@Override
public void Accept(Visitor visitor) {
visitor.vistTeacher(this);
}
}
- 适用性
Visitor 模式适用于:- 一个对象结构包含很多类对象 ,它们有不同的接口,而用户想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作 ,而又想要避免这些操作"污染"这些对象的类。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。