# 设计模式简介
- 设计模式 (DesignPattern) 是对面向对象设计中反复出现的问题的解决方案。
- 这个术语是在 1990 年代由 ErichGamma 等人从建筑设计领域引入到计算机科学中来的。
- 算法不是设计模式,因为算法致力于解决问题而非设计问题。
- 设计模式通常描述了一组相互紧密作用的类与对象。
- 设计模式提供一种讨论软件设计的公共语言,使得熟练设计者的设计经验可以被初学者和其他设计者掌握。
- 设计模式还为软件重构提供了目标。
- 随着软件开发社群对设计模式的兴趣日益增长,已经出版了一些相关的专著,定期召开相应的研讨会。
- 而且 WardCunningham 为此发明了 WikiWiki 用来交流设计模式的经验。
- 总之设计模式就是为了解决某类重复出现的问题而出现的一套成功或有效的解决方案。
# 设计模式的七大原则
# 开闭原则 (Open Close Principle)
- 对扩展开放,对修改关闭。
- 在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。
- 简言之,是为了使程序的扩展性好,易于维护和升级。
- 想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
# 开闭原则案例 - 搜狗皮肤
/** | |
* 皮肤抽象类 | |
* @author LightRain | |
*/ | |
public abstract class AbstractSkin { | |
/** | |
* 扩展皮肤方法 | |
*/ | |
public abstract void display(); | |
} |
/** | |
* 默认皮肤实现类 | |
*/ | |
public class DefaultSkin extends AbstractSkin { | |
@Override | |
public void display() { | |
System.out.println("默认皮肤"); | |
} | |
} |
/** | |
* 自定义皮肤实现类 | |
*/ | |
public class HeimaSkin extends AbstractSkin { | |
@Override | |
public void display() { | |
System.out.println("黑马程序员"); | |
} | |
} |
/** | |
* 搜狗输入法模拟类 聚合 AbstractSkin | |
*/ | |
public class SougouInput { | |
private AbstractSkin skin; | |
public void setSkin(AbstractSkin skin) { | |
this.skin = skin; | |
} | |
public void display() { | |
skin.display(); | |
} | |
} |
/** | |
* 开闭原则测试类 | |
*/ | |
public class Client { | |
public static void main(String[] args) { | |
// 创建搜狗对象 | |
SougouInput input = new SougouInput(); | |
// 创建默认皮肤对象 | |
// DefaultSkin skin = new DefaultSkin(); | |
// 创建搜狗对象自定义皮肤实现类对象 | |
HeimaSkin skin = new HeimaSkin(); | |
// 设置皮肤 | |
input.setSkin(skin); | |
// 显示皮肤 | |
input.display(); | |
} | |
} |
# 里氏代换原则 (Liskov Substitution Principle)
- 里氏代换原则是面向对象设计的基本原则之一。
- 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。
- LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。
- 里氏代换原则是对开闭原则的补充。
- 实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
# 里氏代换原则案例
# after
/** | |
* 定义长方形以及正方形接口实现里氏代替 | |
*/ | |
public interface Quadrilateral { | |
// 长 | |
double getLength(); | |
// 宽 | |
double getWidth(); | |
} |
/** | |
* 长方形类 | |
*/ | |
public class Rectangle implements Quadrilateral { | |
private double length; | |
private double width; | |
public void setLength(double length) { | |
this.length = length; | |
} | |
public void setWidth(double width) { | |
this.width = width; | |
} | |
@Override | |
public double getLength() { | |
return length; | |
} | |
@Override | |
public double getWidth() { | |
return width; | |
} | |
} |
/** | |
* 正方形类 | |
*/ | |
public class Square implements Quadrilateral { | |
private double size; | |
public double getSize() { | |
return size; | |
} | |
public void setSize(double size) { | |
this.size = size; | |
} | |
@Override | |
public double getLength() { | |
return size; | |
} | |
@Override | |
public double getWidth() { | |
return size; | |
} | |
} |
/** | |
* 里氏代换原则测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建长方形 | |
Rectangle r = new Rectangle(); | |
r.setLength(10); | |
r.setWidth(5); | |
resize(r); | |
pln(r); | |
System.out.println("================================================================"); | |
// 创建正方形 | |
Square s = new Square(); | |
s.setSize(10); | |
pln(s); | |
} | |
/** | |
* 扩宽方法 | |
*/ | |
public static void resize(design.patterns.里氏代换原则.after.Rectangle rectangle) { | |
// 判断宽如果比长小则进行扩宽操作 | |
while (rectangle.getWidth() <= rectangle.getLength()) { | |
rectangle.setWidth(rectangle.getWidth() + 1); | |
} | |
} | |
/** | |
* 打印长和宽 | |
*/ | |
public static void pln(Quadrilateral quadrilateral) { | |
System.out.println(quadrilateral.getLength()); | |
System.out.println(quadrilateral.getWidth()); | |
} | |
} |
# before
/** | |
* 矩形类 | |
*/ | |
public class Rectangle { | |
private Double lenght; | |
private Double width; | |
public Double getLenght() { | |
return lenght; | |
} | |
public void setLenght(Double lenght) { | |
this.lenght = lenght; | |
} | |
public Double getWidth() { | |
return width; | |
} | |
public void setWidth(Double width) { | |
this.width = width; | |
} | |
} |
/** | |
* 正方形类 | |
*/ | |
public class Square extends Rectangle { | |
@Override | |
public void setLenght(Double lenght) { | |
super.setLenght(lenght); | |
super.setWidth(lenght); | |
} | |
@Override | |
public void setWidth(Double width) { | |
super.setLenght(width); | |
super.setWidth(width); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建长方形 | |
Rectangle r = new Rectangle(); | |
r.setLenght(10.0); | |
r.setWidth(5.0); | |
resize(r); | |
pln(r); | |
System.out.println("===================="); | |
// 创建正方形 | |
Square s = new Square(); | |
s.setLenght(5.0); | |
s.setWidth(5.0); | |
resize(s); | |
pln(s); | |
} | |
/** | |
* 扩宽方法 | |
*/ | |
public static void resize(Rectangle rectangle) { | |
// 判断宽如果比长小则进行扩宽操作 | |
while (rectangle.getWidth() <= rectangle.getLenght()) { | |
rectangle.setWidth(rectangle.getWidth() + 1); | |
} | |
} | |
/** | |
* 打印长和宽 | |
*/ | |
public static void pln(Rectangle rectangle) { | |
System.out.println(rectangle.getLenght()); | |
System.out.println(rectangle.getWidth()); | |
} | |
} |
# 依赖倒转原则 (Dependence Inversion Principle)
- 这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
# 依赖倒转原则案例
# after
/** | |
* Cpu 接口 | |
*/ | |
public interface CPU { | |
/** | |
* 运行方法 | |
*/ | |
void run(); | |
} |
/** | |
* 硬盘接口 | |
*/ | |
public interface HardDisk { | |
/** | |
* 保存方法 | |
*/ | |
void save(String data); | |
/** | |
* 获取硬盘数据方法 | |
*/ | |
String get(); | |
} |
/** | |
* 内存条接口 | |
*/ | |
public interface Memory { | |
/** | |
* 保存方法 | |
*/ | |
void save(); | |
} |
/** | |
* Cpu 具体实现类 | |
*/ | |
public class InterCpu implements CPU { | |
@Override | |
public void run() { | |
System.out.println("使用InterCPU"); | |
} | |
} |
/** | |
* 硬盘具体实现类 | |
*/ | |
public class XiJieHardDisk implements HardDisk { | |
@Override | |
public void save(String data) { | |
System.out.println("使用希捷硬盘存储数据为: " + data); | |
} | |
@Override | |
public String get() { | |
return "希捷"; | |
} | |
} |
/** | |
* 硬盘具体实现类 | |
*/ | |
public class SanXingDisk implements HardDisk { | |
@Override | |
public void save(String data) { | |
System.out.println("使用三星硬盘储存数据: " + data); | |
} | |
@Override | |
public String get() { | |
return "三星"; | |
} | |
} |
/** | |
* 内存条具体实现类 | |
*/ | |
public class KingstonMemory implements Memory { | |
@Override | |
public void save() { | |
System.out.println("使用金士顿内存条"); | |
} | |
} |
/** | |
* 将所有计算机配件组合进来 | |
*/ | |
public class Computer { | |
private HardDisk disk; | |
private CPU cpu; | |
private Memory memory; | |
public HardDisk getDisk() { | |
return disk; | |
} | |
public void setDisk(HardDisk disk) { | |
this.disk = disk; | |
} | |
public CPU getCpu() { | |
return cpu; | |
} | |
public void setCpu(CPU cpu) { | |
this.cpu = cpu; | |
} | |
public Memory getMemory() { | |
return memory; | |
} | |
public void setMemory(Memory memory) { | |
this.memory = memory; | |
} | |
public void run() { | |
System.out.println("运行电脑"); | |
System.out.println("开机读取数据:" + disk.get()); | |
cpu.run(); | |
memory.save(); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建组件 | |
HardDisk disk = new XiJieHardDisk(); | |
CPU cpu = new InterCpu(); | |
Memory memory = new KingstonMemory(); | |
// 创建电脑 | |
Computer computer = new Computer(); | |
computer.setDisk(disk); | |
computer.setCpu(cpu); | |
computer.setMemory(memory); | |
computer.run(); | |
} | |
} |
# before
/** | |
* Cpu 类 | |
*/ | |
public class InterCPU { | |
public void run() { | |
System.out.println("使用InterCPU"); | |
} | |
} |
/** | |
* 内存条类 | |
*/ | |
public class KingstonMemory { | |
public void save() { | |
System.out.println("使用金士顿内存条"); | |
} | |
} |
/** | |
* 硬盘类 | |
*/ | |
public class XiJieHardDisk { | |
public void save(String data) { | |
System.out.println("使用希捷硬盘存储数据为: " + data); | |
} | |
public String get() { | |
System.out.println("使用希捷硬盘获取数据"); | |
return "数据"; | |
} | |
} |
/** | |
* 计算机类 | |
*/ | |
public class Computer { | |
private XiJieHardDisk hardDisk; | |
private InterCPU cpu; | |
private KingstonMemory memory; | |
public XiJieHardDisk getHardDisk() { | |
return hardDisk; | |
} | |
public void setHardDisk(XiJieHardDisk hardDisk) { | |
this.hardDisk = hardDisk; | |
} | |
public InterCPU getCpu() { | |
return cpu; | |
} | |
public void setCpu(InterCPU cpu) { | |
this.cpu = cpu; | |
} | |
public KingstonMemory getMemory() { | |
return memory; | |
} | |
public void setMemory(KingstonMemory memory) { | |
this.memory = memory; | |
} | |
public void run() { | |
System.out.println("运行电脑"); | |
String data = hardDisk.get(); | |
System.out.println(data); | |
cpu.run(); | |
memory.save(); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建组件 | |
XiJieHardDisk x = new XiJieHardDisk(); | |
InterCPU c = new InterCPU(); | |
KingstonMemory memory = new KingstonMemory(); | |
// 创建电脑 | |
Computer computer = new Computer(); | |
// 组装 | |
computer.setHardDisk(x); | |
computer.setCpu(c); | |
computer.setMemory(memory); | |
// 运行 | |
computer.run(); | |
} | |
} |
# 接口隔离原则 (Interface Segregation Principle)
- 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。
- 它还有另外一个意思是:降低类之间的耦合度。
- 由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
# 接口隔离原则案例
# after
/** | |
* 防盗接口 | |
*/ | |
public interface AntiTheft { | |
void antiTheft(); | |
} |
/** | |
* 防火接口 | |
*/ | |
public interface FirePrevention { | |
void firePrevention(); | |
} |
/** | |
* 防水接口 | |
*/ | |
public interface Waterproof { | |
void waterproof(); | |
} |
/** | |
* 防盗门具体实现类 | |
*/ | |
public class ChuanZhiSafetyDoor implements AntiTheft { | |
@Override | |
public void antiTheft() { | |
System.out.println("防盗"); | |
} | |
} |
/** | |
* 防盗门具体实现类 | |
*/ | |
public class ChuanZhiSafetyDoor implements AntiTheft { | |
@Override | |
public void antiTheft() { | |
System.out.println("防盗"); | |
} | |
} |
/** | |
* 安全门具体实现类 | |
*/ | |
public class HeiMaSafetyDoor implements AntiTheft, Waterproof, FirePrevention { | |
@Override | |
public void firePrevention() { | |
System.out.println("防火"); | |
} | |
@Override | |
public void waterproof() { | |
System.out.println("防水"); | |
} | |
@Override | |
public void antiTheft() { | |
System.out.println("防盗"); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
ChuanZhiSafetyDoor c = new ChuanZhiSafetyDoor(); | |
c.antiTheft(); | |
HeiMaSafetyDoor h = new HeiMaSafetyDoor(); | |
h.antiTheft(); | |
h.firePrevention(); | |
h.waterproof(); | |
} | |
} |
# before
/** | |
* 安全门接口 | |
*/ | |
public interface SafetyDoor { | |
/** | |
* 防火 | |
*/ | |
void firePrevention(); | |
/** | |
* 防水 | |
*/ | |
void waterproof(); | |
/** | |
* 防盗 | |
*/ | |
void antiTheft(); | |
} |
public class HeiMaSafetyDoor implements SafetyDoor { | |
@Override | |
public void firePrevention() { | |
System.out.println("防火"); | |
} | |
@Override | |
public void waterproof() { | |
System.out.println("防水"); | |
} | |
@Override | |
public void antiTheft() { | |
System.out.println("防盗"); | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
HeiMaSafetyDoor heima = new HeiMaSafetyDoor(); | |
heima.antiTheft(); | |
heima.waterproof(); | |
heima.waterproof(); | |
} | |
} |
# 迪米特法则 - 又称最少知道原则 (Demeter Principle)
- 最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
# 迪米特法则案例
/** | |
* 经纪人类 | |
*/ | |
public class Agent { | |
private Star star; | |
private Fnas fnas; | |
private Company company; | |
public void setStar(Star star) { | |
this.star = star; | |
} | |
public void setFnas(Fnas fnas) { | |
this.fnas = fnas; | |
} | |
public void setCompany(Company company) { | |
this.company = company; | |
} | |
/** | |
* 粉丝和明星见面 | |
*/ | |
public void meeting() { | |
System.out.println(star.getName() + "和粉丝" + fnas.getName() + "见面了"); | |
} | |
/** | |
* 明星和媒体洽谈 | |
*/ | |
public void business() { | |
System.out.println(star.getName() + "和媒体" + company.getName() + "洽谈"); | |
} | |
} |
/** | |
* 媒体类 | |
*/ | |
public class Company { | |
private String name; | |
public Company(String name) { | |
this.name = name; | |
} | |
public String getName() { | |
return name; | |
} | |
} |
/** | |
* 粉丝类 | |
*/ | |
public class Fnas { | |
private String name; | |
public Fnas(String name) { | |
this.name = name; | |
} | |
public String getName() { | |
return name; | |
} | |
} |
/** | |
* 明星类 | |
*/ | |
public class Star { | |
private String name; | |
public Star(String name) { | |
this.name = name; | |
} | |
public String getName() { | |
return name; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建经纪人类 | |
Agent agent = new Agent(); | |
// 创建明星 | |
Star star = new Star("林青霞"); | |
// 创建粉丝 | |
Fnas fnas = new Fnas("风清扬"); | |
// 创建媒体 | |
Company company = new Company("黑马传媒"); | |
agent.setStar(star); | |
agent.setFnas(fnas); | |
agent.setCompany(company); | |
agent.meeting(); | |
agent.business(); | |
} | |
} |
# 合成复用原则 (Composite Reuse Principle)
- 合成复用原则是指:尽量使用合成 / 聚合的方式,而不是使用继承。
# 单一职责原则 (Single responsibility principle)
- 一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中,另外一种定义:就一个类而言,应该仅有一个引起它变化的原因。
# 设计模式类型
# 创建型模式 (Creational Patterns)
- 创建型模式 (都是用来帮助我们创建对象的),这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式而不是使用
new
关键字直接实例化对象。 - 这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
- 主要包括:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
# 单例模式 (Singleton Pattern)
- 保证一个类仅有一个对象,并提供一个访问它的全局访问点。
# 饿汉式
- 类加载就会导致该单例对象被创建
# demo1
/** | |
* 饿汉式:静态成员变量 | |
*/ | |
public class Singleton { | |
//1. 私有构造方法 | |
private Singleton() { | |
} | |
//2. 在本类中创建本类对象 | |
private static Singleton instance = new Singleton(); | |
//3. 提供一个公共的访问方式,让外界获取该对象 | |
public static Singleton getInstance() { | |
return instance; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
/** | |
* 判断两个对象是否同一个 | |
*/ | |
Singleton instance = Singleton.getInstance(); | |
Singleton instance2 = Singleton.getInstance(); | |
System.out.println(instance == instance2); | |
} | |
} |
# demo2
/** | |
* 饿汉式:静态代码块 | |
*/ | |
public class Singleton { | |
//1. 私有构造方法 | |
private Singleton() { | |
} | |
//2. 声明 Singleton 类型的变量 | |
private static Singleton instance;//null | |
//3. 在静态代码块中进行赋值 | |
static { | |
instance = new Singleton(); | |
} | |
// 对外提供获取该类对象的方法 | |
public static Singleton getInstance() { | |
return instance; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
/** | |
* 判断两个对象是否同一个 | |
*/ | |
Singleton instance = Singleton.getInstance(); | |
Singleton instance2 = Singleton.getInstance(); | |
System.out.println(instance == instance2); | |
} | |
} |
# 懒汉式
- 类加载不会导致该单例对象被创建,而是首次使用该对象时才会创建
# demo1
/** | |
* 懒汉式:线程不安全 | |
*/ | |
public class Singleton { | |
//1. 私有构造方法 | |
private Singleton() { | |
} | |
//2. 声明 Singleton 类型的变量 instance | |
private static Singleton instance; | |
//3. 对外提供访问方式 | |
public static Singleton getInstance() { | |
// 判断 instance 是否为 null, 如果为 null, 说明还没有创建 Singleton 类的对象 | |
// 如果没有则创建一个并返回,如果有直接返回 | |
if (instance == null) { | |
instance = new Singleton(); | |
} | |
return instance; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
/** | |
* 判断两个对象是否同一个 | |
*/ | |
Singleton instance = Singleton.getInstance(); | |
Singleton instance2 = Singleton.getInstance(); | |
System.out.println(instance == instance2); | |
} | |
} |
# demo2
/** | |
* 懒汉式:线程安全的 | |
*/ | |
public class Singleton { | |
//1. 私有构造方法 | |
private Singleton() { | |
} | |
//2. 声明 Singleton 类型的变量 instance | |
private static Singleton instance; | |
//3. 对外提供访问方式 | |
public static synchronized Singleton getInstance() { | |
// 判断 instance 是否为 null, 如果为 null, 说明还没有创建 Singleton 类的对象 | |
// 如果没有则创建一个并返回,如果有直接返回 | |
if (instance == null) { | |
instance = new Singleton(); | |
} | |
return instance; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
/** | |
* 判断两个对象是否同一个 | |
*/ | |
Singleton instance = Singleton.getInstance(); | |
Singleton instance2 = Singleton.getInstance(); | |
System.out.println(instance == instance2); | |
} | |
} |
# demo3
/** | |
* 懒汉式:双重检查锁 | |
* 再来讨论一下懒汉模式中加锁的问题,对于 getInstance () 方法来说 | |
* 绝大部分的操作都是读操作,读操作是线程安全的,所以 | |
* 我们没必让每个线程必须持有锁才能调用该方法,我们需要调整加锁的时机。由此也产生了一种新的实现模式:双重检查锁模式 | |
* volatile: 禁止 JVM 指令重排操作 | |
* 添加 volatile 关键字之后的双重检查锁模式是一种比较好的单例实现模式,能够保证在多线程的情况下线程安全也不会有性能问题。 | |
*/ | |
public class Singleton { | |
//1. 私有构造方法 | |
private Singleton() { | |
} | |
//2. 声明 Singleton 类型的变量 instance | |
private static volatile Singleton instance; | |
//3. 对外提供访问方式 | |
public static Singleton getInstance() { | |
// 第一次判断,如果 instance 的值不为 null,不需要抢占锁,直接返回对象 | |
if (instance == null) { | |
synchronized (Singleton.class) { | |
// 第二次判断 | |
if (instance == null) { | |
instance = new Singleton(); | |
} | |
} | |
} | |
return instance; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
/** | |
* 判断两个对象是否同一个 | |
*/ | |
Singleton instance = Singleton.getInstance(); | |
Singleton instance2 = Singleton.getInstance(); | |
System.out.println(instance == instance2); | |
} | |
} |
# demo4
/** | |
* 懒汉式:静态内部类,线程安全的并且比双重检查锁简介 | |
* 静态内部类单例模式中实例由内部类创建,由于 TM 在加载外部类的过程中,是不会加载静态内部类的,只有内部类的属性 / 方法被调用时才会被加载,并初始化其静态属性。静态属性由于被 static | |
* 修饰,保证只被实例化一次,并且严格保证实例化顺序。 | |
* 说明: | |
* 第一次加载 singleton 类时不会去初始化 INSTANCE,只有第一次调用 getInstance,虚拟机加载 SingletonHolder 并初始化 INSTANCE,这样不仅能确保线程安全,也能保证 singleton 类的唯一性。 | |
* 小结: | |
* 静态内部类单例模式是一种优秀的单例模式,是开源项目中比较常用的一种单例模式。在没有加任何锁的情况下,保证了多线程下的安全,并且没有任何性能影响和空间的浪费。 | |
*/ | |
public class Singleton { | |
//1. 私有构造 | |
private Singleton() { | |
} | |
//2. 定义一个静态内部类 | |
private static class SingletonHolder { | |
//3. 在内部类中声明并初始化外部类 | |
private static final Singleton INSTANCE = new Singleton(); | |
} | |
//4. 提供公共的访问方法 | |
public static Singleton getInstance() { | |
return SingletonHolder.INSTANCE; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
/** | |
* 判断两个对象是否同一个 | |
*/ | |
Singleton instance = Singleton.getInstance(); | |
Singleton instance2 = Singleton.getInstance(); | |
System.out.println(instance == instance2); | |
} | |
} |
# 枚举式
- 枚举类实现单例模式是极力推荐的单例实现模式,因为枚举类型是线程安全的。
- 并且只会装载一次,设计者充分的利用了枚举的这个特性来实现单例模式。
- 枚举的写法非常简单,而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。
/** | |
* 枚举方式实现单例模式 | |
* 枚举类实现单例模式是极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。 | |
* 说明:枚举方式属于饿汉式,在不考虑内存浪费的情况下首选枚举方式 | |
*/ | |
public enum Singleton { | |
INSTANCE; | |
} |
public class Main { | |
public static void main(String[] args) { | |
Singleton instance = Singleton.INSTANCE; | |
Singleton instance2 = Singleton.INSTANCE; | |
System.out.println(instance == instance2); | |
} | |
} |
# 工厂模式 (Factory Pattern)
- 定义一个用于创建对象的接口,让子类决定将哪一个类实例化,工厂模式使一个类的实例化延迟到其子类。
- 主要包括:工厂方法模式、抽象工厂模式、简单工厂模式、模式扩展
# 工厂方法模式
- 针对上例中的缺点,使用工厂方法模式就可以完美的解决,完全遵循开闭原则。
# 概念
- 定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工
- 方法使一个产品类的实例化延迟到其工厂的子类。
# 结构
# 工厂方法模式的主要角色:
- 抽象工厂 (Abstract Factory)︰提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。。具体工厂 (
ConcreteEactory)︰主要是实现抽象工厂中的抽象方法,完成具体产品的创建。 - 抽象产品 (Product)︰定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品 (ConcreteProduct): 实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
# 代码案例
/** | |
* @author LightRain | |
* 咖啡工厂接口 | |
*/ | |
public interface CoffeeFactory { | |
/** | |
* 创建咖啡对象方法 | |
* | |
* @return Coffee | |
*/ | |
Coffee createCoffee(); | |
} |
/** | |
* @author LightRain | |
* 咖啡抽象类 | |
*/ | |
public abstract class Coffee { | |
/** | |
* 咖啡吗名称 | |
* @return String | |
*/ | |
public abstract String getName(); | |
/** | |
* 加糖 | |
*/ | |
public void addsugar() { | |
System.out.println("加糖"); | |
} | |
/** | |
* 加奶 | |
*/ | |
public void addMilk() { | |
System.out.println("加奶"); | |
} | |
} |
/** | |
* 美式咖啡 | |
* @author LightRain | |
*/ | |
public class AmericanCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "美式咖啡"; | |
} | |
} |
/** | |
* @author LightRain | |
* 卡布奇诺咖啡 | |
*/ | |
public class CacpuccinoCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "卡布奇诺咖啡"; | |
} | |
} |
/** | |
* 拿铁咖啡 | |
*/ | |
public class LatteCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "拿铁咖啡"; | |
} | |
} |
/** | |
* @author LightRain | |
* 美式咖啡工厂,专门生产美式咖啡 | |
*/ | |
public class AmericanCoffeeFactory implements CoffeeFactory { | |
@Override | |
public Coffee createCoffee() { | |
return new AmericanCoffee(); | |
} | |
} |
/** | |
* @author LightRain | |
* 卡布奇诺咖啡工厂 | |
*/ | |
public class CacpuccinoCoffeeFactory implements CoffeeFactory { | |
@Override | |
public Coffee createCoffee() { | |
return new CacpuccinoCoffee(); | |
} | |
} |
/** | |
* @author LightRain | |
* 拿铁咖啡工厂,专门生产拿铁咖啡 | |
*/ | |
public class LatteCoffeeFactory implements CoffeeFactory { | |
@Override | |
public Coffee createCoffee() { | |
return new LatteCoffee(); | |
} | |
} |
/** | |
* @author LightRain | |
* 咖啡店类 | |
*/ | |
public class CoffeeStore { | |
private CoffeeFactory factory; | |
public void setFactory(CoffeeFactory factory) { | |
this.factory = factory; | |
} | |
/** | |
* 点咖啡方法 | |
* @return Coffee | |
*/ | |
public Coffee orderCoffee() { | |
Coffee coffee = factory.createCoffee(); | |
coffee.addsugar(); | |
coffee.addMilk(); | |
return coffee; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建咖啡店 | |
CoffeeStore store = new CoffeeStore(); | |
// 创建具体咖啡工厂 | |
CoffeeFactory factory = new CacpuccinoCoffeeFactory(); | |
store.setFactory(factory); | |
// 点咖啡 | |
Coffee coffee = store.orderCoffee(); | |
System.out.println(coffee.getName()); | |
} | |
} |
# 抽象工厂模式
# 优点:
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
# 缺点:
- 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
# 使用场景
当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。
如:输入法换皮肤,一整套一起换。生成不同操作系统的程序。
# 代码案例
/** | |
* @author LightRain | |
* 甜品工厂接口类 | |
*/ | |
public interface DessertFactory { | |
/** | |
* 生产咖啡功能 | |
* | |
* @return Coffee | |
*/ | |
Coffee createCoffee(); | |
/** | |
* 生产甜品功能 | |
* | |
* @return Dessert | |
*/ | |
Dessert createDessert(); | |
} |
/** | |
* @author LightRain | |
* 甜品抽象类 | |
*/ | |
public abstract class Dessert { | |
abstract void show(); | |
} |
/** | |
* @author LightRain | |
* 咖啡抽象类 | |
*/ | |
public abstract class Coffee { | |
/** | |
* 咖啡吗名称 | |
* @return String | |
*/ | |
public abstract String getName(); | |
/** | |
* 加糖 | |
*/ | |
public void addsugar() { | |
System.out.println("加糖"); | |
} | |
/** | |
* 加奶 | |
*/ | |
public void addMilk() { | |
System.out.println("加奶"); | |
} | |
} |
/** | |
* 美式咖啡 | |
* @author LightRain | |
*/ | |
public class AmericanCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "美式咖啡"; | |
} | |
} |
/** | |
* 拿铁咖啡 | |
*/ | |
public class LatteCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "拿铁咖啡"; | |
} | |
} |
/** | |
* @author LightRain | |
* 提拉米苏类 | |
*/ | |
public class Trimisu extends Dessert { | |
@Override | |
void show() { | |
System.out.println("提拉米苏"); | |
} | |
} |
/** | |
* @author LightRain | |
* 抹茶慕斯类 | |
*/ | |
public class MatchaMousse extends Dessert { | |
@Override | |
void show() { | |
System.out.println("抹茶慕斯"); | |
} | |
} |
/** | |
* @author LightRain | |
* 美式风味工厂实现类 | |
* 可以生成美式咖啡和抹茶慕斯 | |
*/ | |
public class AmericanDessertFactory implements DessertFactory { | |
/** | |
* 生产美式咖啡 | |
* | |
* @return Coffee | |
*/ | |
@Override | |
public Coffee createCoffee() { | |
return new AmericanCoffee(); | |
} | |
/** | |
* 生产抹茶慕斯 | |
* | |
* @return Dessert | |
*/ | |
@Override | |
public Dessert createDessert() { | |
return new MatchaMousse(); | |
} | |
} |
/** | |
* @author LightRain | |
* 意大利风味工厂实现类 | |
*/ | |
public class ItalyDessertFactory implements DessertFactory { | |
/** | |
* 生产拿铁咖啡 | |
* | |
* @return Coffee | |
*/ | |
@Override | |
public Coffee createCoffee() { | |
return new LatteCoffee(); | |
} | |
/** | |
* 生产提拉米苏 | |
* | |
* @return Dessert | |
*/ | |
@Override | |
public Dessert createDessert() { | |
return new Trimisu(); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
ItalyDessertFactory factory = new ItalyDessertFactory(); | |
// AmericanDessertFactory factory = new AmericanDessertFactory(); | |
// 拿铁咖啡 | |
Coffee coffee = factory.createCoffee(); | |
// 提拉米苏 | |
Dessert dessert = factory.createDessert(); | |
String name = coffee.getName(); | |
dessert.show(); | |
System.out.println(name); | |
System.out.println("================================================"); | |
AmericanDessertFactory amf = new AmericanDessertFactory(); | |
// 美式咖啡 | |
Coffee amfCoffee = amf.createCoffee(); | |
String name1 = amfCoffee.getName(); | |
// 抹茶慕斯 | |
Dessert amfDessert = amf.createDessert(); | |
amfDessert.show(); | |
System.out.println(name1); | |
} | |
} |
# 简单工厂模式
- 简单工厂模式定义为:简单工厂模式又称为静态工厂方法模型,它属于类创建型模式。
- 在简单工厂模式中,可以根据参数的不同返回不同类的实例。
- 简单工厂专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
- 简单工厂模式包含如下角色:
- Factory (工厂角色)
- 工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有实例的内部逻辑。
- 工厂类可以直接被外界直接调用,创建所需的产品对象。
- 在工厂类中提供了静态的工厂方法 factoryMethod(),它返回一个抽象产品类 Product,所有的具体产品都是抽象产品的子类。
- Product (抽象产品角色)
- 抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个工厂方法,因为所有创建的具体产品对象都是其子类对象。
- ConcreteProduct (具体产品类)
- 具体产品角色是简单工厂模式的创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
- 每一个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的抽象方法 。
- Factory (工厂角色)
# 代码案例
/** | |
* @author LightRain | |
* 咖啡类 | |
*/ | |
public abstract class Coffee { | |
/** | |
* 咖啡吗名称 | |
* @return String | |
*/ | |
public abstract String getName(); | |
/** | |
* 加糖 | |
*/ | |
public void addsugar() { | |
System.out.println("加糖"); | |
} | |
/** | |
* 加奶 | |
*/ | |
public void addMilk() { | |
System.out.println("加奶"); | |
} | |
} |
/** | |
* 美式咖啡 | |
* @author LightRain | |
*/ | |
public class AmericanCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "美式咖啡"; | |
} | |
} |
/** | |
* 拿铁咖啡 | |
*/ | |
public class LatteCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "拿铁咖啡"; | |
} | |
} |
/** | |
* 简单工厂类 | |
* | |
* @author LightRain | |
*/ | |
public class SimpleCoffeeFactory { | |
public static Coffee createCoffee(String type) { | |
// 声明 Coffee 类型的变量吗,根据不同类型创建不同的子类 Coffee 对象 | |
Coffee coffee = null; | |
if ("anerican".equals(type)) { | |
coffee = new AmericanCoffee(); | |
} else if ("latte".equals(type)) { | |
coffee = new LatteCoffee(); | |
} else { | |
throw new RuntimeException("对不起没有该品种咖啡!"); | |
} | |
return coffee; | |
} | |
} |
/** | |
* @author LightRain | |
* 咖啡店类 | |
*/ | |
public class CoffeeStore { | |
public Coffee orderCoffee(String type) { | |
// 创建咖啡工厂 | |
// SimpleCoffeeFactory factory = new SimpleCoffeeFactory(); | |
// 调用生产咖啡的方法 | |
// Coffee coffee = factory.createCoffee(type); | |
Coffee coffee = SimpleCoffeeFactory.createCoffee(type); | |
coffee.addsugar(); | |
coffee.addMilk(); | |
return coffee; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
CoffeeStore coffee = new CoffeeStore(); | |
Coffee latte = coffee.orderCoffee("latte"); | |
System.out.println(latte.getName()); | |
} | |
} |
# 模式扩展
/** | |
* @author LightRain | |
* 咖啡抽象类 | |
*/ | |
public abstract class Coffee { | |
/** | |
* 咖啡吗名称 | |
* @return String | |
*/ | |
public abstract String getName(); | |
/** | |
* 加糖 | |
*/ | |
public void addsugar() { | |
System.out.println("加糖"); | |
} | |
/** | |
* 加奶 | |
*/ | |
public void addMilk() { | |
System.out.println("加奶"); | |
} | |
} |
/** | |
* 美式咖啡 | |
* @author LightRain | |
*/ | |
public class AmericanCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "美式咖啡"; | |
} | |
} |
/** | |
* @author LightRain | |
* 卡布奇诺咖啡类 | |
*/ | |
public class CacpuccinoCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "卡布奇诺咖啡"; | |
} | |
} |
/** | |
* 拿铁咖啡 | |
*/ | |
public class LatteCoffee extends Coffee { | |
@Override | |
public String getName() { | |
return "拿铁咖啡"; | |
} | |
} |
import java.io.InputStream; | |
import java.util.HashMap; | |
import java.util.Properties; | |
import java.util.Set; | |
/** | |
* @author LightRain | |
* 静态成员变量用来存储创建的对象(键存储的是名称,值存储的是对应的对象),而读取配置文件以及创建对象写在静态代码块中,目的就是只需要执行一次。 | |
*/ | |
public class CoffeeFactory { | |
/* | |
加载配置文件,获取配置中的全类名,并创建该类的对象进行储存 | |
*/ | |
/** | |
* 1. 定义容器对象储存咖啡类 | |
*/ | |
private static HashMap<String, Coffee> map = new HashMap<String, Coffee>(); | |
/* | |
2. 加载配置文件,只需要加载一次 | |
*/ | |
static { | |
//2.1 创建 Properties | |
Properties properties = new Properties(); | |
//2.2 获取字节码文件 | |
InputStream is = Coffee.class.getClassLoader().getResourceAsStream("bean.properties"); | |
try { | |
//2.3 调用 Properties 中的 load 方法进行加载 | |
properties.load(is); | |
//3. 从 Properties 集合中获取全类名并创建对象 | |
Set<Object> keySet = properties.keySet(); | |
for (Object key : keySet) { | |
// 获取全类名 | |
String className = properties.getProperty((String) key); | |
// 通过反射技术创建对象 | |
Class<?> clazz = Class.forName(className); | |
// 通过反射创建对象 | |
Coffee coffee = (Coffee) clazz.getDeclaredConstructor().newInstance(); | |
// 将名称和对象储存到容器中 | |
map.put((String) key, coffee); | |
} | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
/** | |
* 根据名称获取对象 | |
* | |
* @param name 对象名称 | |
* @return Coffee | |
*/ | |
public static Coffee createCoffee(String name) { | |
// 通过 Map 获取对象 | |
return map.get(name); | |
} | |
} |
/** | |
* 静态成员变量用来存储创建的对象(键存储的是名称,值存储的是对应的对象),而读取配置文件以及创建对象写在静态代码块中,目的就是只需要执行一次。 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
Coffee american = CoffeeFactory.createCoffee("american"); | |
String americanName = american.getName(); | |
System.out.println(americanName); | |
System.out.println("==================="); | |
Coffee latte = CoffeeFactory.createCoffee("latte"); | |
String latteName = latte.getName(); | |
System.out.println(latteName); | |
System.out.println("==================="); | |
Coffee cacpuccino = CoffeeFactory.createCoffee("cacpuccino"); | |
String cacpuccinoName = cacpuccino.getName(); | |
System.out.println(cacpuccinoName); | |
} | |
} |
# 建造者模式 (Builder Pattern)
- 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- 优点
- 建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。
- 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 可以更加精细地控制产品的创建过程,将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 建造者模式很容易进行扩展,如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。符合开闭原则。
- 缺点
- 造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 使用场景
- 建造者 (Builder) 模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
- 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
- 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
# 建造者模式代码案例
/** | |
* @author LightRain | |
* 构建者抽象类,因为是共有属性 | |
*/ | |
public abstract class Builder { | |
/** | |
* 声明产品类对象 | |
*/ | |
protected Bike bike = new Bike(); | |
/** | |
* 构架车架 | |
*/ | |
public abstract void buildFrame(); | |
/** | |
* 构建车座 | |
*/ | |
public abstract void buildSeat(); | |
/** | |
* 构建自行车 | |
* | |
* @return Bike | |
*/ | |
public abstract Bike createBike(); | |
} |
/** | |
* @author LightRain | |
* 产品对象 | |
*/ | |
public class Bike { | |
/** | |
* 车架 | |
*/ | |
private String frame; | |
/** | |
* 车座 | |
*/ | |
private String seat; | |
public String getFrame() { | |
return frame; | |
} | |
public void setFrame(String frame) { | |
this.frame = frame; | |
} | |
public String getSeat() { | |
return seat; | |
} | |
public void setSeat(String seat) { | |
this.seat = seat; | |
} | |
} |
/** | |
* @author LightRain | |
* 指挥者类,用于指挥构建 | |
*/ | |
public class Director { | |
/** | |
* 声明 Builder 对象 | |
*/ | |
private final Builder builder; | |
public Director(Builder builder) { | |
this.builder = builder; | |
} | |
/** | |
* 组装自行车 | |
* @return Bike | |
*/ | |
public Bike cunstruct() { | |
builder.buildFrame(); | |
builder.buildSeat(); | |
return builder.createBike(); | |
} | |
} |
/** | |
* @author LightRain | |
* 摩拜单车构建者,用来构建摩拜单车对象 | |
*/ | |
public class MobikeBuilder extends Builder { | |
@Override | |
public void buildFrame() { | |
bike.setFrame("碳纤维车架"); | |
} | |
@Override | |
public void buildSeat() { | |
bike.setSeat("真皮车座"); | |
} | |
@Override | |
public Bike createBike() { | |
return bike; | |
} | |
} |
/** | |
* @author LightRain | |
* ofo 单车构建者,用来构建 ofo 单车对象 | |
*/ | |
public class OfoBuilder extends Builder { | |
@Override | |
public void buildFrame() { | |
bike.setFrame("ofo车架"); | |
} | |
@Override | |
public void buildSeat() { | |
bike.setSeat("ofo车座"); | |
} | |
@Override | |
public Bike createBike() { | |
return bike; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建指挥者 创建膜拜单车 | |
Director director = new Director(new MobikeBuilder()); | |
// 让指挥者,指挥自行车组装 | |
Bike bike = director.cunstruct(); | |
System.out.println(bike.getFrame()); | |
System.out.println(bike.getSeat()); | |
} | |
} |
# 模式扩展
/** | |
* @author LightRain | |
* 手机类 使用局部建造者模式创建 | |
*/ | |
public class Phone { | |
private String cpu; | |
private String screen; | |
private String memory; | |
private String mainboard; | |
/** | |
* 私有构造方法 | |
* | |
* @param builder 建造者 | |
*/ | |
private Phone(Builder builder) { | |
this.cpu = builder.cpu; | |
this.screen = builder.screen; | |
this.memory = builder.memory; | |
this.mainboard = builder.mainboard; | |
} | |
@Override | |
public String toString() { | |
return "Phone{" + | |
"cpu='" + cpu + '\'' + | |
", screen='" + screen + '\'' + | |
", memory='" + memory + '\'' + | |
", mainboard='" + mainboard + '\'' + | |
'}'; | |
} | |
/** | |
* 建造者模式静态内部类 | |
*/ | |
public static final class Builder { | |
private String cpu; | |
private String screen; | |
private String memory; | |
private String mainboard; | |
public Builder cpu(String cpu) { | |
this.cpu = cpu; | |
return this; | |
} | |
public Builder screen(String screen) { | |
this.screen = screen; | |
return this; | |
} | |
public Builder memory(String memory) { | |
this.memory = memory; | |
return this; | |
} | |
public Builder mainboard(String mainboard) { | |
this.mainboard = mainboard; | |
return this; | |
} | |
public Phone build() { | |
return new Phone(this); | |
} | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
/* | |
使用局部建造者实现链式编程 | |
*/ | |
Phone build = new Phone.Builder() | |
.cpu("1") | |
.screen("2") | |
.memory("3") | |
.mainboard("4") | |
.build(); | |
System.out.println(build.toString()); | |
} | |
} |
# 原型模式 (Prototype Pattern)
- 通过复制现有实例来创建新的实例,无需知道相应类的信息。
- 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
- 适用场景:相似对象,只是对象属性有差异,通过对象的深复制或浅复制构建新对象,直接应用。
- 深拷贝和浅拷贝
- 浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
- 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。
- clone 明显是深复制,clone 出来的对象是是不能去影响原型对象的。
# 浅克隆
# demo1
/** | |
* @author LightRain | |
* 浅克隆奖状案例 | |
*/ | |
public class Citation implements Cloneable { | |
private String name; | |
public void setName(String name) { | |
this.name = name; | |
} | |
@Override | |
public Citation clone() throws CloneNotSupportedException { | |
return (Citation) super.clone(); | |
} | |
public void show() { | |
System.out.println(name + "同学,在2020学年第一学期中表现优秀,被评为三好学生。特发此状!"); | |
} | |
} |
/** | |
* 使用场景: | |
* 对象的创建非常复杂,可以使用原型模式快捷的创建对象。 | |
* 性能和安全要求毕竟高。 | |
*/ | |
public class Main { | |
public static void main(String[] args) throws CloneNotSupportedException { | |
// 创建原型对象 | |
Citation citation = new Citation(); | |
// 克隆奖状对象 | |
Citation citation1 = citation.clone(); | |
citation.setName("风清扬"); | |
citation1.setName("林青霞"); | |
citation.show(); | |
citation1.show(); | |
} | |
} |
# demo2
/** | |
* @author LightRain | |
* 继承 Cloneable 重写 clone 方法实现浅克隆 | |
*/ | |
public class Realizetype implements Cloneable { | |
public Realizetype() { | |
System.out.println("具体的原型对象创建成功!"); | |
} | |
@Override | |
protected Realizetype clone() throws CloneNotSupportedException { | |
System.out.println("具体原型复制成功!"); | |
return (Realizetype) super.clone(); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) throws CloneNotSupportedException { | |
// 创建原型对象类 | |
Realizetype r = new Realizetype(); | |
// 调用 Realizetype 类中的 clone 方法进行对象克隆 | |
Realizetype clone = r.clone(); | |
System.out.println("原型对象和克隆出来的对象是否是同一个对象?" + (r == clone)); | |
} | |
} |
# 深克隆
import java.io.Serializable; | |
/** | |
* @author LightRain | |
* 深克隆奖状案例 | |
* 必须:implements Cloneable, Serializable | |
* Cloneable: 重写 clone 的克隆方法 | |
* Serializable: 序列化接口 | |
*/ | |
public class Citation implements Cloneable, Serializable { | |
private Student stu; | |
public Student getStu() { | |
return stu; | |
} | |
public void setStu(Student stu) { | |
this.stu = stu; | |
} | |
@Override | |
public Citation clone() throws CloneNotSupportedException { | |
return (Citation) super.clone(); | |
} | |
public void show() { | |
System.out.println(stu.getName() + "同学,在2020学年第一学期中表现优秀,被评为三好学生。特发此状!"); | |
} | |
} |
import java.io.Serializable; | |
/** | |
* @author LightRain | |
*/ | |
public class Student implements Serializable { | |
/** | |
* 学生姓名 | |
*/ | |
private String name; | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
@Override | |
public String toString() { | |
return "Student{" + | |
"name='" + name + '\'' + | |
'}'; | |
} | |
} |
import java.io.*; | |
/** | |
* @author LightRain | |
* 使用序列化实现深克隆 | |
*/ | |
public class Main { | |
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException { | |
// 创建原型对象 | |
Citation citation = new Citation(); | |
// 创建学生对象 | |
Student stu = new Student(); | |
stu.setName("张三"); | |
citation.setStu(stu); | |
// 创建对象输出流对象 | |
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\深克隆\\t.txt")); | |
// 将原型对象写入到文件内 | |
oos.writeObject(citation); | |
// 释放资源 | |
oos.close(); | |
// 读取文件 创建对象输入流对象 | |
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\深克隆\\t.txt")); | |
ObjectInputStream ois2 = new ObjectInputStream(new FileInputStream("E:\\深克隆\\t.txt")); | |
// 读取对象 | |
Citation citation1 = (Citation) ois.readObject(); | |
Citation citation2 = (Citation) ois2.readObject(); | |
// 释放资源 | |
ois.close(); | |
citation1.getStu().setName("李四"); | |
citation2.getStu().setName("王五"); | |
citation2.show(); | |
citation1.show(); | |
citation.show(); | |
} | |
} |
# 结构型模式 (Structural Patterns)
# 适配器模式 (Adapter Pattern)
- 将一个类的接口转换成客户希望的另一个接口。
- Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 主要分为三类
- 适用场景
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。
# 类适配器模式
- 顾名思义,通过适配器通过类来实现,以类来继承和实现接口的方式,来获取被适配类的信息并转换输出重写到适配接口。
/** | |
* @author LightRain | |
* 目标接口 | |
*/ | |
public interface SDCard { | |
/** | |
* 读取 SD 卡数据 | |
* | |
* @return String | |
*/ | |
String readSD(); | |
/** | |
* 写入 SD 卡数据 | |
* | |
* @param msg 数据 | |
*/ | |
void writeSD(String msg); | |
} |
/** | |
* @author LightRain | |
* 适配者类的接口 | |
*/ | |
public interface TFCard { | |
/** | |
* 从 TF 卡中读取数据 | |
* | |
* @return String | |
*/ | |
String readTf(); | |
/** | |
* 往 TF 卡中写数据 | |
* | |
* @param msg 数据 | |
*/ | |
void writeTf(String msg); | |
} |
/** | |
* @author LightRain | |
* 具体的 SD 卡 | |
*/ | |
public class SDCardImpl implements SDCard { | |
@Override | |
public String readSD() { | |
String msg = "SDCard read msg: Hello world!"; | |
return msg; | |
} | |
@Override | |
public void writeSD(String msg) { | |
System.out.println("SDCard write msg: " + msg); | |
} | |
} |
/** | |
* @author LightRain | |
* 适配者类 | |
*/ | |
public class TFCardImpl implements TFCard { | |
@Override | |
public String readTf() { | |
String mag = "TFCard read msg: Hello world!"; | |
return mag; | |
} | |
@Override | |
public void writeTf(String msg) { | |
System.out.println("TFCard write msg: " + msg); | |
} | |
} |
/** | |
* @author 适配器类 | |
*/ | |
public class SDAdapterTF extends TFCardImpl implements SDCard { | |
@Override | |
public String readSD() { | |
System.out.println("adapter read tf card\n"); | |
return readTf(); | |
} | |
@Override | |
public void writeSD(String msg) { | |
System.out.println("adapter write tf card"); | |
writeTf(msg); | |
} | |
} |
/** | |
* @author LightRain | |
* 计算机类 | |
*/ | |
public class Computer { | |
/** | |
* 读取 SD 卡数据 | |
* @param card SD 卡接口 | |
* @return String | |
*/ | |
public String readSD(SDCard card) { | |
if (card == null) { | |
throw new NullPointerException("sd card is not null"); | |
} | |
return card.readSD(); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建计算机对象 | |
Computer computer = new Computer(); | |
// 从 SD 卡中读取数据 | |
String msg = computer.readSD(new SDCardImpl()); | |
System.out.println(msg); | |
System.out.println("================================================================"); | |
// 使用计算机读取 TF 卡数据 | |
// 定义适配器类 | |
String msg1 = computer.readSD(new SDAdapterTF()); | |
System.out.println(msg1); | |
} | |
} |
# 接口适配器模式
- 接口适配器也称缺省适配器模式,适用于一个接口不想使用其所有的方法的情况。
- 当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法)。
- 那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
/** | |
* 电脑配件接口 | |
*/ | |
public interface Computer { | |
String cpu(); | |
void network(); | |
void disk(); | |
void memory(); | |
} |
/** | |
* 适配器类 | |
*/ | |
public abstract class Adapter implements Computer { | |
@Override | |
public String cpu() { | |
return null; | |
} | |
@Override | |
public void network() { | |
} | |
@Override | |
public void disk() { | |
} | |
@Override | |
public void memory() { | |
} | |
} |
/** | |
* @author LightRain | |
* 接口适配器 | |
* 注意:还有一个适配器模式是接口适配器模式。当不希望实现一个接口中所有的方法时, | |
* 可以创建一个抽象类 Adapter,实现所有方法。而此时我们只需要继承该抽象类即可。 | |
*/ | |
public class ComputerImpl extends Adapter { | |
@Override | |
public String cpu() { | |
return "只实现CPU方法"; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
ComputerImpl c = new ComputerImpl(); | |
String cpu = c.cpu(); | |
System.out.println(cpu); | |
} | |
} |
# 对象适配器模式
- 顾名思义,通过实例对象(构造器传递)来实现适配器,而不是再用继承,其余基本同类适配器。
/** | |
* @author LightRain | |
* 目标接口 | |
*/ | |
public interface SDCard { | |
/** | |
* 读取 SD 卡数据 | |
* | |
* @return String | |
*/ | |
String readSD(); | |
/** | |
* 写入 SD 卡数据 | |
* | |
* @param msg 数据 | |
*/ | |
void writeSD(String msg); | |
} |
/** | |
* @author LightRain | |
* 适配者类的接口 | |
*/ | |
public interface TFCard { | |
/** | |
* 从 TF 卡中读取数据 | |
* | |
* @return String | |
*/ | |
String readTf(); | |
/** | |
* 往 TF 卡中写数据 | |
* | |
* @param msg 数据 | |
*/ | |
void writeTf(String msg); | |
} |
/** | |
* @author LightRain | |
* 具体的 SD 卡 | |
*/ | |
public class SDCardImpl implements SDCard { | |
@Override | |
public String readSD() { | |
String msg = "SDCard read msg: Hello world!"; | |
return msg; | |
} | |
@Override | |
public void writeSD(String msg) { | |
System.out.println("SDCard write msg: " + msg); | |
} | |
} |
/** | |
* @author LightRain | |
* 适配者类 | |
*/ | |
public class TFCardImpl implements TFCard { | |
@Override | |
public String readTf() { | |
String mag = "TFCard read msg: Hello world!"; | |
return mag; | |
} | |
@Override | |
public void writeTf(String msg) { | |
System.out.println("TFCard write msg: " + msg); | |
} | |
} |
/** | |
* @author 适配器类 | |
*/ | |
public class SDAdapterTF implements SDCard { | |
/** | |
* 声明 TFCardImpl 类 | |
*/ | |
private TFCardImpl tfCard; | |
public SDAdapterTF(TFCardImpl tfCard) { | |
this.tfCard = tfCard; | |
} | |
@Override | |
public String readSD() { | |
System.out.println("adapter read tf card"); | |
return tfCard.readTf(); | |
} | |
@Override | |
public void writeSD(String msg) { | |
System.out.println("adapter write tf card"); | |
tfCard.writeTf(msg); | |
} | |
} |
/** | |
* @author LightRain | |
* 计算机类 | |
*/ | |
public class Computer { | |
/** | |
* 读取 SD 卡数据 | |
* @param card SD 卡接口 | |
* @return String | |
*/ | |
public String readSD(SDCard card) { | |
if (card == null) { | |
throw new NullPointerException("sd card is not null"); | |
} | |
return card.readSD(); | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
// 创建计算机对象 | |
Computer computer = new Computer(); | |
// 从 SD 卡中读取数据 | |
String msg = computer.readSD(new SDCardImpl()); | |
System.out.println(msg); | |
System.out.println("================================================================"); | |
// 使用该电脑读取 TF 卡中的数据 | |
// 创建适配器对象 | |
SDAdapterTF sdAdapterTF = new SDAdapterTF(new TFCardImpl()); | |
String msg1 = computer.readSD(sdAdapterTF); | |
System.out.println(msg1); | |
} | |
} |
# 桥接模式 (Bridge Pattern)
- 将抽象部分与它的实现部分分离,使他们都可以独立地变化。
- 好处
- 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
- 如:如果现在还有一种视频文件类型 wmv,我们只需要再定义一个类实现 videoFile 接口即可。
- 其他类不需要发生变化,实现细节对客户透明
- 使用场景
- 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。
- 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
- 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。
- 避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
# 桥接模式代码案例
/** | |
* @author LightRain | |
* 视频文件 (实现化角色) | |
*/ | |
public interface VideoFile { | |
/** | |
* 解码器 | |
* | |
* @param filename 文件名称 | |
*/ | |
void decode(String filename); | |
} |
/** | |
* 抽象的操作系统类 (抽象化角色) | |
*/ | |
public abstract class OpratingSystem { | |
/** | |
* 声明 videoFile 变量 | |
*/ | |
protected VideoFile videoFile; | |
public OpratingSystem(VideoFile videoFile) { | |
this.videoFile = videoFile; | |
} | |
/** | |
* 播放视频文件 | |
* | |
* @param filename 视频文件 | |
*/ | |
public abstract void play(String filename); | |
} |
/** | |
* @author LightRain | |
* Rmvb 视频文件 (具体的实现化角色) | |
*/ | |
public class RmvbFile implements VideoFile { | |
@Override | |
public void decode(String filename) { | |
System.out.println("Rmvb视频文件:" + filename); | |
} | |
} |
/** | |
* @author LightRain | |
* Avi 视频文件 (具体的实现化角色) | |
*/ | |
public class AviFile implements VideoFile { | |
@Override | |
public void decode(String filename) { | |
System.out.println("Avi视频文件:" + filename); | |
} | |
} |
/** | |
* @author LightRain | |
* 扩展抽象化角色 (Windows 操作系统) | |
*/ | |
public class Windows extends OpratingSystem { | |
public Windows(VideoFile videoFile) { | |
super(videoFile); | |
} | |
@Override | |
public void play(String filename) { | |
videoFile.decode(filename); | |
} | |
} |
/** | |
* @author LightRain | |
* 扩展抽象化角色 (Mac 操作系统) | |
*/ | |
public class Mac extends OpratingSystem { | |
public Mac(VideoFile videoFile) { | |
super(videoFile); | |
} | |
@Override | |
public void play(String filename) { | |
videoFile.decode(filename); | |
} | |
} |
/** | |
* @author LightRain | |
* 扩展抽象化角色 (Linux 操作系统) | |
*/ | |
public class Linux extends OpratingSystem { | |
public Linux(VideoFile videoFile) { | |
super(videoFile); | |
} | |
@Override | |
public void play(String filename) { | |
videoFile.decode(filename); | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
// 多态创建操作系统 | |
OpratingSystem ops = new Mac(new RmvbFile()); | |
ops.play("你的名字"); | |
Windows ops1 = new Windows(new AviFile()); | |
ops1.play("天气之子"); | |
} | |
} |
# 组合模式 (Composite Pattern)
- 将对象组合成树形结构以表示 “部分 - 整体” 的层次结构。
- Composite 使得客户对单个对象和复合对象的使用具有一致性。
# 组合模式代码案例
/** | |
* @author LightRain | |
* 菜单组件:属于抽象根节点 | |
*/ | |
public abstract class MenuComponent { | |
/** | |
* 菜单组件名称 | |
*/ | |
protected String name; | |
/** | |
* 菜单组件层级 | |
*/ | |
protected int level; | |
/** | |
* 添加子菜单 | |
* | |
* @param component 组件 | |
*/ | |
public void add(MenuComponent component) { | |
throw new UnsupportedOperationException(); | |
} | |
/** | |
* 移除子菜单 | |
* | |
* @param component 组件 | |
*/ | |
public void remove(MenuComponent component) { | |
throw new UnsupportedOperationException(); | |
} | |
/** | |
* 获取指定的子菜单 | |
* | |
* @param index 索引 | |
* @return MenuComponent | |
*/ | |
public MenuComponent getChild(int index) { | |
throw new UnsupportedOperationException(); | |
} | |
/** | |
* 获取菜单或者菜单项的名称 | |
* | |
* @return String | |
*/ | |
public String getName() { | |
return name; | |
} | |
/** | |
* 打印菜单名称的方法(包含子菜单和菜单项) | |
*/ | |
public abstract void print(); | |
} |
/** | |
* @author LightRain | |
* 菜单项类:属于叶子节点 | |
*/ | |
public class MenuItem extends MenuComponent { | |
public MenuItem(String name, int level) { | |
this.name = name; | |
this.level = level; | |
} | |
@Override | |
public void print() { | |
for (int i = 0; i < level; i++) { | |
System.out.print("-"); | |
} | |
// 打印菜单项的名称 | |
System.out.println(name); | |
} | |
} |
/** | |
* 菜单类:属于树枝节点 | |
*/ | |
public class Menu extends MenuComponent { | |
/** | |
* 菜单可以有多个子菜单或者子菜单项 | |
*/ | |
private final List<MenuComponent> menuComponents = new ArrayList<MenuComponent>(); | |
public Menu(String name, int level) { | |
this.name = name; | |
this.level = level; | |
} | |
@Override | |
public void add(MenuComponent component) { | |
menuComponents.add(component); | |
} | |
@Override | |
public void remove(MenuComponent component) { | |
menuComponents.remove(component); | |
} | |
@Override | |
public MenuComponent getChild(int index) { | |
return menuComponents.get(index); | |
} | |
@Override | |
public void print() { | |
for (int i = 0; i < level; i++) { | |
System.out.print("-"); | |
} | |
// 打印菜单名称 | |
System.out.println(name); | |
// 打印子菜单或者菜单项 | |
for (MenuComponent component : menuComponents) { | |
component.print(); | |
} | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
// 创建菜单树 | |
MenuComponent menu1 = new Menu("菜单管理", 2); | |
menu1.add(new MenuItem("访问页面", 3)); | |
menu1.add(new MenuItem("展开菜单", 3)); | |
menu1.add(new MenuItem("编辑菜单", 3)); | |
menu1.add(new MenuItem("删除菜单", 3)); | |
menu1.add(new MenuItem("新增菜单", 3)); | |
MenuComponent menu2 = new Menu("权限管理", 2); | |
menu2.add(new MenuItem("页面访问", 3)); | |
menu2.add(new MenuItem("提交保存", 3)); | |
MenuComponent menu3 = new Menu("角色管理", 2); | |
menu3.add(new MenuItem("新增角色", 3)); | |
menu3.add(new MenuItem("修改角色", 3)); | |
// 创建一级菜单 | |
MenuComponent component = new Menu("系统管理", 1); | |
// 将二级菜单添加到一级菜单内 | |
component.add(menu1); | |
component.add(menu2); | |
component.add(menu3); | |
component.print(); | |
} | |
} |
# 装饰模式 (Decorator Pattern)
- 动态地给一个对象添加一些额外的职责。
- 就扩展功能而言,Decorator 模式比生成子类的方式更为灵活。
# 装饰模式代码案例
/** | |
* @author LightRain | |
* 快餐抽象类 (抽象构建角色) | |
*/ | |
public abstract class FastFood { | |
/** | |
* 价格 | |
*/ | |
private float price; | |
/** | |
* 描述 | |
*/ | |
private String desc; | |
public FastFood() { | |
} | |
public FastFood(float price, String desc) { | |
this.price = price; | |
this.desc = desc; | |
} | |
public float getPrice() { | |
return price; | |
} | |
public void setPrice(float price) { | |
this.price = price; | |
} | |
public String getDesc() { | |
return desc; | |
} | |
public void setDesc(String desc) { | |
this.desc = desc; | |
} | |
/** | |
* 计算价格 | |
* @return float | |
*/ | |
public abstract float cost(); | |
} |
/** | |
* @author LightRain | |
* 装饰者类 (抽象装饰者角色) | |
*/ | |
public abstract class Garnish extends FastFood { | |
/** | |
* 声明快餐类的变量 | |
*/ | |
private final FastFood fastFood; | |
public FastFood getFastFood() { | |
return fastFood; | |
} | |
public Garnish(FastFood fastFood) { | |
this.fastFood = fastFood; | |
} | |
public Garnish(FastFood fastFood, float price, String desc) { | |
super(price, desc); | |
this.fastFood = fastFood; | |
} | |
} |
/** | |
* @author LightRain | |
* 炒面类 (具体构建角色) | |
*/ | |
public class FriedNoodles extends FastFood { | |
public FriedNoodles() { | |
super(5, "炒面"); | |
} | |
@Override | |
public float cost() { | |
return getPrice(); | |
} | |
} |
/** | |
* @author LightRain | |
* 炒饭类 (具体构建角色) | |
*/ | |
public class FriedRice extends FastFood { | |
public FriedRice() { | |
super(10, "炒饭"); | |
} | |
@Override | |
public float cost() { | |
return getPrice(); | |
} | |
} |
/** | |
* @author LightRain | |
* 培根类 (具体的装饰者角色) | |
*/ | |
public class Bacon extends Garnish { | |
public Bacon(FastFood fastFood) { | |
super(fastFood, 2, "培根"); | |
} | |
/** | |
* 计算价格 | |
* | |
* @return float | |
*/ | |
@Override | |
public float cost() { | |
return getPrice() + getFastFood().getPrice(); | |
} | |
@Override | |
public String getDesc() { | |
return super.getDesc() + getFastFood().getDesc(); | |
} | |
} |
/** | |
* @author LightRain | |
* 鸡蛋类 (具体的装饰者角色) | |
*/ | |
public class Egg extends Garnish { | |
public Egg(FastFood fastFood) { | |
super(fastFood, 1, "鸡蛋"); | |
} | |
/** | |
* 计算价格 | |
* | |
* @return float | |
*/ | |
@Override | |
public float cost() { | |
return getPrice() + getFastFood().getPrice(); | |
} | |
@Override | |
public String getDesc() { | |
return super.getDesc() + getFastFood().getDesc(); | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
// 点一份炒粉 | |
FriedRice friedRice = new FriedRice(); | |
System.out.println(friedRice.getDesc() + ": " + friedRice.cost() + "元"); | |
System.out.println("==================="); | |
Egg egg = new Egg(friedRice); | |
System.out.println(egg.getDesc() + ": " + egg.cost() + "元"); | |
System.out.println("方式二顶层抽象类接收"); | |
FastFood food = new FriedNoodles(); | |
System.out.println(food.getDesc() + ": " + food.cost() + "元"); | |
food = new Egg(food); | |
System.out.println(food.getDesc() + ": " + food.cost() + "元"); | |
} | |
} |
# 外观模式 (Facade Pattern)
- 为子系统中的一组接口提供一个一致的接口。
- Façade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
# 外观模式代码案例
/** | |
* @author LightRain | |
* 共有属性开关 | |
*/ | |
public abstract class Switch { | |
/** | |
* 开启 | |
*/ | |
public abstract void on(); | |
/** | |
* 关闭 | |
*/ | |
public abstract void off(); | |
} |
/** | |
* @author LightRain | |
* 电视 | |
*/ | |
public class Tv extends Switch { | |
@Override | |
public void on() { | |
System.out.println("开启电视..."); | |
} | |
@Override | |
public void off() { | |
System.out.println("关闭电视..."); | |
} | |
} |
/** | |
* @author LightRain | |
* 小爱智能音响 | |
*/ | |
public class XiaoAi { | |
private Light light; | |
private Tv tv; | |
public XiaoAi() { | |
light = new Light(); | |
tv = new Tv(); | |
} | |
public void say(String message) { | |
if (message.contains("开启")) { | |
on(); | |
} else if (message.contains("关闭")) { | |
off(); | |
} else { | |
System.out.println("小爱还不会"); | |
} | |
} | |
private void on() { | |
light.on(); | |
tv.on(); | |
} | |
private void off() { | |
light.off(); | |
tv.off(); | |
} | |
} |
/** | |
* @author LightRain | |
* 电灯 | |
*/ | |
public class Light extends Switch { | |
@Override | |
public void on() { | |
System.out.println("开启开灯..."); | |
} | |
@Override | |
public void off() { | |
System.out.println("关闭开灯..."); | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
XiaoAi ai = new XiaoAi(); | |
ai.say("开启"); | |
ai.say("关闭"); | |
} | |
} |
# 享元模式 (Flyweight Pattern)
- 运用共享技术有效地支持大量细粒度的对象。
# 享元模式代码案例
/** | |
* @author LightRain | |
* 抽象享元角色 | |
*/ | |
public abstract class AbstractBox { | |
/** | |
* 获取图形的方法 | |
* | |
* @return String | |
*/ | |
public abstract String getShape(); | |
/** | |
* 显示图形及颜色 | |
* | |
* @param color 颜色 | |
*/ | |
public void display(String color) { | |
System.out.println("方块形状:" + getShape() + "颜色:" + color); | |
} | |
} |
/** | |
* @author LightRain | |
* I 图形类 (具体享元角色) | |
*/ | |
public class IBox extends AbstractBox { | |
@Override | |
public String getShape() { | |
return "I"; | |
} | |
} |
/** | |
* @author LightRain | |
* L 图形类 (具体享元角色) | |
*/ | |
public class LBox extends AbstractBox { | |
@Override | |
public String getShape() { | |
return "L"; | |
} | |
} |
/** | |
* @author LightRain | |
* O 图形类 (具体享元角色) | |
*/ | |
public class OBox extends AbstractBox { | |
@Override | |
public String getShape() { | |
return "O"; | |
} | |
} |
import java.util.HashMap; | |
/** | |
* @author LightRain | |
* 工厂类:为单例模式 | |
*/ | |
public class BoxFactory { | |
private HashMap<String, AbstractBox> map; | |
/** | |
* 构造方法中进行初始化操作 | |
*/ | |
private BoxFactory() { | |
map = new HashMap<>(); | |
map.put("I", new IBox()); | |
map.put("L", new LBox()); | |
map.put("O", new OBox()); | |
} | |
/** | |
* 提供一个方法获取工厂对象 | |
* | |
* @return BoxFactory | |
*/ | |
public static BoxFactory getInstance() { | |
return boxFactory; | |
} | |
private static BoxFactory boxFactory = new BoxFactory(); | |
/** | |
* 根据图形获取图形对象 | |
* | |
* @param name 图形名称 | |
* @return AbstractBox | |
*/ | |
public AbstractBox getShape(String name) { | |
return map.get(name); | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
AbstractBox box1 = BoxFactory.getInstance().getShape("I"); | |
box1.display("红色"); | |
AbstractBox box2 = BoxFactory.getInstance().getShape("L"); | |
box2.display("绿色"); | |
AbstractBox box3 = BoxFactory.getInstance().getShape("O"); | |
box3.display("蓝色"); | |
AbstractBox box4 = BoxFactory.getInstance().getShape("O"); | |
box4.display("紫色"); | |
System.out.println(box3 == box4); | |
} | |
} |
# 代理模式 (Proxy Pattern)
- 为其他对象提供一个代理以控制对这个对象的访问。
# 动态代理
- 动态代理更加灵活。
- 我们不需要针对每个目标类都单独创建一个代理类。
- 并且也不需要我们必须实现接口,通过动态代理类我们可以完成全部的代理功能。
- JDK 动态代理和 CGLIB 动态代理都是 Java 中的动态代理技术,但它们的实现方式不同。
- 总的来说,JDK 动态代理适用于代理实现了接口的类,而 CGLIB 动态代理适用于代理没有实现接口的类。
# CGLIB 动态代理
- CGLIB 动态代理是基于继承的代理,它不要求被代理的类实现接口,代理类继承被代理类并重写被代理类的方法。
- CGLIB 动态代理使用 ASM 框架实现,因此它的效率比 JDK 动态代理略低,但它可以代理没有实现接口的类。
# CGLIB 动态代理代码案例
/** | |
* @author LightRain | |
* 火车站类 | |
*/ | |
public class TrainStation { | |
public void sell() { | |
System.out.println("火车站卖票"); | |
} | |
} |
import org.springframework.cglib.proxy.Enhancer; | |
import org.springframework.cglib.proxy.MethodInterceptor; | |
import org.springframework.cglib.proxy.MethodProxy; | |
import java.lang.reflect.Method; | |
/** | |
* @author LightRain | |
* CGLIB 动态代理 | |
* 代理对象工厂,用来获取代理对象 | |
*/ | |
public class ProxyFactor implements MethodInterceptor { | |
/** | |
* 声明目标类变量 | |
*/ | |
private final TrainStation trainStation = new TrainStation(); | |
/** | |
* 动态代理方法 | |
* | |
* @return TrainStation | |
*/ | |
public TrainStation getProxyObject() { | |
// 创建 Enhancer 对象,类似于 JDK 中的 Proxy 对象 | |
Enhancer enhancer = new Enhancer(); | |
// 设置父类字节码对象 | |
enhancer.setSuperclass(TrainStation.class); | |
// 设置回调函数 | |
enhancer.setCallback(this); | |
// 创建代理对象 | |
TrainStation proxyObject = (TrainStation) enhancer.create(); | |
return proxyObject; | |
} | |
@Override | |
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { | |
System.out.println("代售点收取一定服务费用!CGLib动态代理"); | |
Object invoke = method.invoke(trainStation, args); | |
return invoke; | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
// 创建代理工厂对象 | |
ProxyFactor factor = new ProxyFactor(); | |
// 获取代理对象 | |
TrainStation proxyObject = factor.getProxyObject(); | |
proxyObject.sell(); | |
} | |
} |
# JDK 动态代理
- JDK 动态代理是基于接口的代理,它要求被代理的类必须实现一个接口,代理类实现该接口并在代理类中调用被代理类的方法。
- JDK 动态代理使用 Java 自带的反射机制实现,因此它的效率比较高。
# JDK 动态代理代码案例
import java.util.HashSet; | |
/** | |
* 定义规范 | |
*/ | |
public interface SellTickets { | |
HashSet<String> sell(); | |
} |
import java.util.HashSet; | |
/** | |
* @author LightRain | |
* 火车站类 | |
*/ | |
public class TrainStation implements SellTickets { | |
@Override | |
public HashSet<String> sell() { | |
System.out.println("火车站卖票"); | |
HashSet<String> set = new HashSet<String>(); | |
set.add("1"); | |
set.add("2"); | |
set.add("3"); | |
return set; | |
} | |
} |
import java.lang.reflect.InvocationHandler; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Proxy; | |
/** | |
* @author LightRain | |
* 获取代理工厂类 | |
* 代理类也实现了对应的接口 | |
*/ | |
public class ProxyFactory { | |
/** | |
* 声明目标对象 | |
*/ | |
private final TrainStation trainStation = new TrainStation(); | |
/** | |
* 获取代理对象方法 | |
* | |
* @return SellTickets | |
*/ | |
public SellTickets getSellTickets() { | |
// 获取代理 | |
/* | |
ClassLoader loader: 类加载器,用于加载代理类,可以通过目标对象获取类加载器 | |
Class<?>[] interfaces: 代理类实现的接口的字节码对象 | |
InvocationHandler: 代理对象调用处理程序 | |
*/ | |
SellTickets proxyObject = (SellTickets) Proxy.newProxyInstance( | |
trainStation.getClass().getClassLoader(), | |
trainStation.getClass().getInterfaces(), | |
new InvocationHandler() { | |
/* | |
Object proxy:代理对象。和 proxyObject 对象是同一个对象,在 invoke 方法中基本不用 | |
Method method:对接口中的方法进行封装的 method 对象 | |
Object [] args:调用方法的实际参数 | |
返回值:方法的返回值 | |
*/ | |
@Override | |
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | |
System.out.println("invoke执行了"); | |
System.out.println("代售点收取服务费用JDK动态代理!"); | |
// 执行目标对象方法,使用反射调用 | |
// 目标对象 实际参数 | |
Object obj = method.invoke(trainStation, args);//invoke 就可以获取方法的返回值 | |
return obj; | |
} | |
} | |
); | |
// 返回代理对象 | |
return proxyObject; | |
} | |
} |
import java.util.HashSet; | |
public class Main { | |
public static void main(String[] args) { | |
// 获取代理工厂 | |
//1. 创建代理工厂 | |
ProxyFactory factory = new ProxyFactory(); | |
//2. 通过 factory 获取代理对象 | |
SellTickets proxyObject = factory.getSellTickets(); | |
//3. 调用方法 | |
HashSet<String> sell = proxyObject.sell(); | |
System.out.println(sell); | |
// 获取代理类名称,代理类在内存中创建,程序结束时释放 | |
System.out.println(proxyObject.getClass()); | |
} | |
} |
# 静态代理
- 静态代理中,我们对目标对象的每个方法的增强都是手动完成的。
- 非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦 (需要对每个目标类都单独写一个代理类)。
- 从 JVM 层面来说,静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。
# 静态代理代码案例
/** | |
* 定义规范 | |
*/ | |
public interface SellTickets { | |
void sell(); | |
} |
/** | |
* @author LightRain | |
* 火车站类 | |
*/ | |
public class TrainStation implements SellTickets { | |
@Override | |
public void sell() { | |
System.out.println("火车站卖票"); | |
} | |
} |
/** | |
* 代售点类 | |
*/ | |
public class ProxyPoint implements SellTickets { | |
private TrainStation trainStation = new TrainStation(); | |
@Override | |
public void sell() { | |
System.out.println("收取服务费"); | |
trainStation.sell(); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建代理对象 | |
ProxyPoint p = new ProxyPoint(); | |
p.sell(); | |
} | |
} |
# 行为型模式 (Behavioral Patterns)
# 模版方法模式 (Template Pattern)
- 定义一个操作中的算法的骨架,而将一些步骤延迟到子类。
- TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
# 模版方法模式代码案例
/** | |
* @author LightRain | |
* 抽象类(定义模板方法和基本方法) | |
*/ | |
public abstract class AsbstractClass { | |
/** | |
* 模板方法定义 | |
*/ | |
public void cookProcess() { | |
pourOil(); | |
heatOil(); | |
pourVegetable(); | |
pourSauce(); | |
fry(); | |
} | |
public void pourOil() { | |
System.out.println("倒油"); | |
} | |
public void heatOil() { | |
System.out.println("热油"); | |
} | |
/** | |
* 倒蔬菜 | |
*/ | |
public abstract void pourVegetable(); | |
/** | |
* 倒调料品 | |
*/ | |
public abstract void pourSauce(); | |
public void fry() { | |
System.out.println("翻炒"); | |
} | |
} |
/** | |
* @author LightRain | |
*/ | |
public class ConcreteClassBaoCai extends AsbstractClass { | |
@Override | |
public void pourVegetable() { | |
System.out.println("下锅的蔬菜是包菜"); | |
} | |
@Override | |
public void pourSauce() { | |
System.out.println("下锅的酱料是辣椒"); | |
} | |
} |
public class ConcreteClassCaiXin extends AsbstractClass { | |
@Override | |
public void pourVegetable() { | |
System.out.println("下锅的蔬菜是菜心"); | |
} | |
@Override | |
public void pourSauce() { | |
System.out.println("下锅的酱料是蒜蓉"); | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
ConcreteClassBaoCai c = new ConcreteClassBaoCai(); | |
c.cookProcess(); | |
ConcreteClassCaiXin c2 = new ConcreteClassCaiXin(); | |
c2.cookProcess(); | |
} | |
} |
# 命令模式 (Command Pattern)
- 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可取消的操作。
- 优点
- 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。
- 增加或删除命令非常方便。
- 采用命令模式增加与删除命令不会影响其他类,它满足 " 开闭原则”,对扩展比较灵活。
- 可以实现宏命令,命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
- 缺点
- 使用命令模式可能会导致某些系统有过多的具体命令类。
- 系统结构更加复杂。
- 使用场景
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
- 系统需要在不同的时间指定请求、将请求排队和执行请求。
- 系统需要支持命令的撤销 (undo) 操作和恢复 (Redo) 操作。
# 命令模式代码案例
/** | |
* @author LightRain | |
* 抽象命令类 | |
*/ | |
public interface Command { | |
/** | |
* 命令方法 | |
*/ | |
void execute(); | |
} |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* @author LightRain | |
* 订单类 | |
*/ | |
public class Order { | |
/** | |
* 餐桌号码 | |
*/ | |
private int diningTable; | |
private Map<String, Integer> foodDir = new HashMap<>(); | |
public int getDiningTable() { | |
return diningTable; | |
} | |
public void setDiningTable(int diningTable) { | |
this.diningTable = diningTable; | |
} | |
public Map<String, Integer> getFoodDir() { | |
return foodDir; | |
} | |
public void setFood(String name, int num) { | |
foodDir.put(name, num); | |
} | |
} |
/** | |
* @author LightRain | |
* 厨师类 | |
*/ | |
public class SeniorChef { | |
public void makeFood(String name, int num) { | |
System.out.println(num + "份" + name); | |
} | |
} |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* @author LightRain | |
* 服务员类 | |
*/ | |
public class Waitor { | |
/** | |
* 持有多个命令对象 | |
*/ | |
private List<Command> commands = new ArrayList<>(); | |
public void setCommand(Command cmd) { | |
commands.add(cmd); | |
} | |
/** | |
* 发起命令功能 | |
*/ | |
public void orderUp() { | |
System.out.println("服务员:来新订单了"); | |
for (Command command : commands) { | |
if (commands != null) { | |
// 调用命令方法 | |
command.execute(); | |
} | |
} | |
} | |
} |
import java.util.Map; | |
import java.util.Set; | |
/** | |
* @author LightRain | |
* 具体命令类 | |
*/ | |
public class OrderCommand implements Command { | |
/** | |
* 定义厨师类 | |
*/ | |
private SeniorChef seniorChef; | |
/** | |
* 定义订单类 | |
*/ | |
private Order order; | |
public OrderCommand(SeniorChef seniorChef, Order order) { | |
this.seniorChef = seniorChef; | |
this.order = order; | |
} | |
@Override | |
public void execute() { | |
System.out.println(order.getDiningTable() + "餐桌的订单"); | |
Map<String, Integer> foodDir = order.getFoodDir(); | |
// 遍历 Map | |
Set<String> keySet = foodDir.keySet(); | |
for (String foodName : keySet) { | |
seniorChef.makeFood(foodName, foodDir.get(foodName)); | |
} | |
System.out.println(order.getDiningTable() + "餐桌的订单已处理完毕!!!"); | |
} | |
} |
public class Main { | |
public static void main(String[] args) { | |
// 创建第一个订单对象 | |
Order order1 = new Order(); | |
order1.setDiningTable(1); | |
order1.setFood("鱼香肉丝", 1); | |
order1.setFood("可口可乐", 1); | |
// 创建第二个订单对象 | |
Order order2 = new Order(); | |
order2.setDiningTable(2); | |
order2.setFood("蛋炒饭", 1); | |
order2.setFood("雪碧", 1); | |
// 创建厨师对象 | |
SeniorChef receiver = new SeniorChef(); | |
// 创建命令对象 | |
OrderCommand orderCommand1 = new OrderCommand(receiver, order1); | |
OrderCommand orderCommand2 = new OrderCommand(receiver, order2); | |
// 创建服务员对象 | |
Waitor invoke = new Waitor(); | |
invoke.setCommand(orderCommand1); | |
invoke.setCommand(orderCommand2); | |
// 执行命令 | |
invoke.orderUp(); | |
} | |
} |
# 迭代器模式 (Iterator Pattern)
- 提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。
# 迭代器模式代码案例
/** | |
* @author LightRain | |
* 抽象聚合角色接口 | |
*/ | |
public interface StudentAggregate { | |
/** | |
* 添加学生功能 | |
* | |
* @param student Student | |
*/ | |
void addStudent(Student student); | |
/** | |
* 删除学生功能 | |
* | |
* @param student Student | |
*/ | |
void removeStudent(Student student); | |
/** | |
* 获取迭代器对象功能 | |
* | |
* @return StudentInterface | |
*/ | |
StudentInterface getStudentInterface(); | |
} |
/** | |
* @author LightRain | |
* 抽象迭代器角色接口 | |
*/ | |
public interface StudentInterface { | |
/** | |
* 判断是否还有元素 | |
* | |
* @return boolean | |
*/ | |
boolean nasNext(); | |
/** | |
* 获取下一个元素 | |
* | |
* @return Student | |
*/ | |
Student next(); | |
} |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* @author LightRain | |
* 具体聚合角色类 | |
*/ | |
public class StudentAggregateImpl implements StudentAggregate { | |
private final List<Student> list = new ArrayList<>(); | |
/** | |
* 添加元素 | |
* | |
* @param student Student | |
*/ | |
@Override | |
public void addStudent(Student student) { | |
list.add(student); | |
} | |
/** | |
* 删除元素 | |
* | |
* @param student Student | |
*/ | |
@Override | |
public void removeStudent(Student student) { | |
list.remove(student); | |
} | |
/** | |
* 获取迭代器对象 | |
* | |
* @return StudentInterface | |
*/ | |
@Override | |
public StudentInterface getStudentInterface() { | |
return new StudentInterfaceImpl(list); | |
} | |
} |
import java.util.List; | |
/** | |
* @author LightRain | |
* 具体迭代器角色类 | |
*/ | |
public class StudentInterfaceImpl implements StudentInterface { | |
/** | |
* 聚合对象 | |
*/ | |
private List<Student> list; | |
/** | |
* 记录遍历元素位置 | |
*/ | |
private int position = 0; | |
public StudentInterfaceImpl(List<Student> list) { | |
this.list = list; | |
} | |
@Override | |
public boolean nasNext() { | |
return position < list.size(); | |
} | |
@Override | |
public Student next() { | |
// 从集合中获取指定位置的元素 | |
Student currentStudent = list.get(position); | |
position++; | |
return currentStudent; | |
} | |
} |
/** | |
* @author LightRain | |
* 学生类 | |
*/ | |
public class Student { | |
/** | |
* 姓名 | |
*/ | |
private String name; | |
/** | |
* 学号 | |
*/ | |
private String number; | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public String getNumber() { | |
return number; | |
} | |
public void setNumber(String number) { | |
this.number = number; | |
} | |
public Student(String name, String number) { | |
this.name = name; | |
this.number = number; | |
} | |
@Override | |
public String toString() { | |
return "Student{" + | |
"name='" + name + '\'' + | |
", number='" + number + '\'' + | |
'}'; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建聚合对象 | |
StudentAggregateImpl aggregate = new StudentAggregateImpl(); | |
// 添加元素 | |
aggregate.addStudent(new Student("张三", "001")); | |
aggregate.addStudent(new Student("李四", "002")); | |
// 遍历聚合对象 | |
//1. 获取迭代器对象 | |
StudentInterface anInterface = aggregate.getStudentInterface(); | |
//2. 遍历 | |
while (anInterface.nasNext()) { | |
//3. 获取元素 | |
Student student = anInterface.next(); | |
System.out.println(student.toString()); | |
} | |
} | |
} |
# 观察者模式 (Observer Pattern)
- 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
# 观察者模式代码案例
/** | |
* @author LightRain | |
* 抽象观察者角色接口 | |
*/ | |
public interface Observer { | |
/** | |
* 主题更新推送 | |
* | |
* @param message String | |
*/ | |
void update(String message); | |
} |
/** | |
* @author LightRain | |
* 抽象主题角色接口 | |
*/ | |
public interface Subject { | |
/** | |
* 添加订阅者(添加观察者对象) | |
* | |
* @param observer Observer | |
*/ | |
void attach(Observer observer); | |
/** | |
* 删除订阅者(删除观察者对象) | |
* | |
* @param observer Observer | |
*/ | |
void detach(Observer observer); | |
/** | |
* 通知订阅者更新消息 | |
* | |
* @param message String | |
*/ | |
void notify(String message); | |
} |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* @author LightRain | |
* 具体主题角色 | |
*/ | |
public class SubscriptionSubject implements Subject { | |
/** | |
* 定义一个集合,用来储存多个观察者对象 | |
*/ | |
private final List<Observer> weixinUserList = new ArrayList<>(); | |
@Override | |
public void attach(Observer observer) { | |
weixinUserList.add(observer); | |
} | |
@Override | |
public void detach(Observer observer) { | |
weixinUserList.remove(observer); | |
} | |
@Override | |
public void notify(String message) { | |
for (Observer observer : weixinUserList) { | |
// 调用观察者中的 update 方法 | |
observer.update(message); | |
} | |
} | |
} |
/** | |
* @author LightRain | |
* 具体观察者角色类 | |
*/ | |
public class WeiXinUser implements Observer { | |
/** | |
* 记录微信名称 | |
*/ | |
private String name; | |
public WeiXinUser(String name) { | |
this.name = name; | |
} | |
@Override | |
public void update(String message) { | |
System.out.println(name + ": " + message); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建公众号对象 | |
SubscriptionSubject subject = new SubscriptionSubject(); | |
// 订阅公众号 | |
subject.attach(new WeiXinUser("小明")); | |
subject.attach(new WeiXinUser("张三")); | |
subject.attach(new WeiXinUser("阿刁")); | |
// 公众号更新,发出消息给订阅者(观察者对象) | |
subject.notify("黑马程序员专栏更新了!"); | |
} | |
} |
# 中介者模式 (Mediator Pattern)
- 用一个中介对象来封装一系列的对象交互。
- 中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
# 中介者模式代码案例
/** | |
* @author LightRain | |
* 抽象同事类 | |
*/ | |
public abstract class Person { | |
protected String name; | |
protected Mediator mediator; | |
public Person(String name, Mediator mediator) { | |
this.name = name; | |
this.mediator = mediator; | |
} | |
} |
/** | |
* @author LightRain | |
* 抽象中介者类 | |
*/ | |
public abstract class Mediator { | |
public abstract void constact(String message, Person person); | |
} |
/** | |
* @author LightRain | |
* 具体同事角色类 租房者 | |
*/ | |
public class Tenant extends Person { | |
public Tenant(String name, Mediator mediator) { | |
super(name, mediator); | |
} | |
/** | |
* 和中介沟通的方法 | |
* | |
* @param message String | |
*/ | |
public void constact(String message) { | |
mediator.constact(message, this); | |
} | |
/** | |
* 获取信息 | |
* | |
* @param message String | |
*/ | |
public void getMessage(String message) { | |
System.out.println("租房者" + name + "获取到的信息是:" + message); | |
} | |
} |
/** | |
* @author LightRain | |
* 具体中介者角色类 | |
*/ | |
public class MediatorStructure extends Mediator { | |
/** | |
* 聚合房主 | |
*/ | |
private HouseOwner houseOwner; | |
/** | |
* 聚合租房者 | |
*/ | |
private Tenant tenant; | |
@Override | |
public void constact(String message, Person person) { | |
if (person == houseOwner) { | |
tenant.getMessage(message); | |
} else { | |
houseOwner.getMessage(message); | |
} | |
} | |
public HouseOwner getHouseOwner() { | |
return houseOwner; | |
} | |
public void setHouseOwner(HouseOwner houseOwner) { | |
this.houseOwner = houseOwner; | |
} | |
public Tenant getTenant() { | |
return tenant; | |
} | |
public void setTenant(Tenant tenant) { | |
this.tenant = tenant; | |
} | |
} |
/** | |
* @author LightRain | |
* 具体的同事角色类 房屋所有者 | |
*/ | |
public class HouseOwner extends Person { | |
public HouseOwner(String name, Mediator mediator) { | |
super(name, mediator); | |
} | |
/** | |
* 和中介沟通的方法 | |
* | |
* @param message String | |
*/ | |
public void constact(String message) { | |
mediator.constact(message, this); | |
} | |
/** | |
* 获取信息 | |
* | |
* @param message String | |
*/ | |
public void getMessage(String message) { | |
System.out.println("房主" + name + "获取到的信息是:" + message); | |
} | |
} |
/** | |
* 测试 | |
* @author LightRain | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建中介者对象 | |
MediatorStructure mediator = new MediatorStructure(); | |
// 创建租房者对象 | |
Tenant tenant = new Tenant("李四", mediator); | |
// 创建房主对象 | |
HouseOwner houseOwner = new HouseOwner("张三", mediator); | |
// 中介者要知道具体房主和租房者信息 | |
mediator.setTenant(tenant); | |
mediator.setHouseOwner(houseOwner); | |
tenant.constact("我要租三室的房子!"); | |
houseOwner.constact("我有三室的房子要租吗?"); | |
} | |
} |
# 备忘录模式 (Memento Pattern)
- 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保持该状态,这样以后就可以将该对象恢复到保存的状态。
# 白箱模式
- 备忘录对象对任何对象都提供一个接口,即 宽接口,备忘录角色所有内部存储的状态对所有对象公开
# 代码案例
/** | |
* 游戏角色(发起人角色) | |
*/ | |
public class GameRole { | |
/** | |
* 生命力 | |
*/ | |
private int vit; | |
/** | |
* 攻击力 | |
*/ | |
private int atk; | |
/** | |
* 防御力 | |
*/ | |
private int def; | |
/** | |
* 初始化 | |
*/ | |
public void initState() { | |
this.vit = 100; | |
this.atk = 100; | |
this.def = 100; | |
} | |
/** | |
* 战斗方法 | |
*/ | |
public void fight() { | |
this.vit = 0; | |
this.atk = 0; | |
this.def = 0; | |
} | |
/** | |
* 保存内部状态 | |
*/ | |
public RoleStateMemento saveState() { | |
return new RoleStateMemento(vit, atk, def); | |
} | |
/** | |
* 恢复内部状态 | |
*/ | |
public void recoverState(RoleStateMemento roleStateMemento) { | |
// 将备忘录对象中储存的状态赋值给当前对象的成员 | |
this.vit = roleStateMemento.getVit(); | |
this.atk = roleStateMemento.getAtk(); | |
this.def = roleStateMemento.getDef(); | |
} | |
/** | |
* 展示状态 | |
*/ | |
public void stateDisplay() { | |
System.out.println("角色生命力:" + vit); | |
System.out.println("角色攻击力:" + atk); | |
System.out.println("角色防御力:" + def); | |
} | |
public int getVit() { | |
return vit; | |
} | |
public void setVit(int vit) { | |
this.vit = vit; | |
} | |
public int getAtk() { | |
return atk; | |
} | |
public void setAtk(int atk) { | |
this.atk = atk; | |
} | |
public int getDef() { | |
return def; | |
} | |
public void setDef(int def) { | |
this.def = def; | |
} | |
} |
/** | |
* 角色状态备忘录 | |
*/ | |
public class RoleStateMemento { | |
/** | |
* 生命力 | |
*/ | |
private int vit; | |
/** | |
* 攻击力 | |
*/ | |
private int atk; | |
/** | |
* 防御力 | |
*/ | |
private int def; | |
public RoleStateMemento(int vit, int atk, int def) { | |
this.vit = vit; | |
this.atk = atk; | |
this.def = def; | |
} | |
public RoleStateMemento() { | |
} | |
public int getVit() { | |
return vit; | |
} | |
public void setVit(int vit) { | |
this.vit = vit; | |
} | |
public int getAtk() { | |
return atk; | |
} | |
public void setAtk(int atk) { | |
this.atk = atk; | |
} | |
public int getDef() { | |
return def; | |
} | |
public void setDef(int def) { | |
this.def = def; | |
} | |
} |
/** | |
* 备忘录管理对象 | |
*/ | |
public class RolestateCaretaker { | |
/** | |
* 声明备忘录角色 | |
*/ | |
private RoleStateMemento roleStateMemento; | |
public RoleStateMemento getRoleStateMemento() { | |
return roleStateMemento; | |
} | |
public void setRoleStateMemento(RoleStateMemento roleStateMemento) { | |
this.roleStateMemento = roleStateMemento; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
System.out.println("-----------------------大战boss前-------------------------"); | |
// 创建游戏角色对象 | |
GameRole gameRole = new GameRole(); | |
// 初始化 | |
gameRole.initState(); | |
// 展示状态 | |
gameRole.stateDisplay(); | |
// 将游戏内部状态进行备份 | |
// 创建管理者角色 | |
RolestateCaretaker rolestateCaretaker = new RolestateCaretaker(); | |
rolestateCaretaker.setRoleStateMemento(gameRole.saveState()); | |
System.out.println("-----------------------大战boss后-------------------------"); | |
// 损耗 | |
gameRole.fight(); | |
gameRole.stateDisplay(); | |
System.out.println("-----------------------恢复之前的状态-----------------------"); | |
gameRole.recoverState(rolestateCaretaker.getRoleStateMemento()); | |
// 展示状态 | |
gameRole.stateDisplay(); | |
} | |
} |
# 黑箱模式
- 备忘录角色对发起人对象提供一个宽接口,而为其他对象提供一个窄接口。
- 在 Java 语言中,实现双重接口的方法就是将备忘录类设计成发起人的内部成员类
# 代码案例
/** | |
* 备忘录接口,对外提供一个窄接口 | |
*/ | |
public interface Memento { | |
} |
/** | |
* 游戏角色(发起人角色) | |
*/ | |
public class GameRole implements Memento { | |
/** | |
* 生命力 | |
*/ | |
private int vit; | |
/** | |
* 攻击力 | |
*/ | |
private int atk; | |
/** | |
* 防御力 | |
*/ | |
private int def; | |
/** | |
* 初始化 | |
*/ | |
public void initState() { | |
this.vit = 100; | |
this.atk = 100; | |
this.def = 100; | |
} | |
/** | |
* 战斗方法 | |
*/ | |
public void fight() { | |
this.vit = 0; | |
this.atk = 0; | |
this.def = 0; | |
} | |
/** | |
* 保存内部状态 | |
*/ | |
public Memento saveState() { | |
return new RoleStateMemento(vit, atk, def); | |
} | |
/** | |
* 恢复内部状态 | |
*/ | |
public void recoverState(Memento memento) { | |
// 向下转性 | |
RoleStateMemento roleStateMemento = (RoleStateMemento) memento; | |
// 将备忘录对象中储存的状态赋值给当前对象的成员 | |
this.vit = roleStateMemento.getVit(); | |
this.atk = roleStateMemento.getAtk(); | |
this.def = roleStateMemento.getDef(); | |
} | |
/** | |
* 展示状态 | |
*/ | |
public void stateDisplay() { | |
System.out.println("角色生命力:" + vit); | |
System.out.println("角色攻击力:" + atk); | |
System.out.println("角色防御力:" + def); | |
} | |
public int getVit() { | |
return vit; | |
} | |
public void setVit(int vit) { | |
this.vit = vit; | |
} | |
public int getAtk() { | |
return atk; | |
} | |
public void setAtk(int atk) { | |
this.atk = atk; | |
} | |
public int getDef() { | |
return def; | |
} | |
public void setDef(int def) { | |
this.def = def; | |
} | |
/** | |
* 黑箱模式 | |
* 将备忘录定义在发起人内部 | |
* 并且为私有方法要实现 Memento 接口 | |
*/ | |
private class RoleStateMemento implements Memento { | |
/** | |
* 生命力 | |
*/ | |
private int vit; | |
/** | |
* 攻击力 | |
*/ | |
private int atk; | |
/** | |
* 防御力 | |
*/ | |
private int def; | |
public RoleStateMemento(int vit, int atk, int def) { | |
this.vit = vit; | |
this.atk = atk; | |
this.def = def; | |
} | |
public RoleStateMemento() { | |
} | |
public int getVit() { | |
return vit; | |
} | |
public void setVit(int vit) { | |
this.vit = vit; | |
} | |
public int getAtk() { | |
return atk; | |
} | |
public void setAtk(int atk) { | |
this.atk = atk; | |
} | |
public int getDef() { | |
return def; | |
} | |
public void setDef(int def) { | |
this.def = def; | |
} | |
} | |
} |
/** | |
* 备忘录管理对象,黑箱模式,面向接口 | |
*/ | |
public class RolestateCaretaker { | |
private Memento memento; | |
public Memento getMemento() { | |
return memento; | |
} | |
public void setMemento(Memento memento) { | |
this.memento = memento; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
System.out.println("-----------------------大战boss前-------------------------"); | |
// 创建游戏角色对象 | |
GameRole gameRole = new GameRole(); | |
// 初始化 | |
gameRole.initState(); | |
// 展示状态 | |
gameRole.stateDisplay(); | |
// 将游戏内部状态进行备份 | |
// 创建管理者角色 | |
RolestateCaretaker rolestateCaretaker = new RolestateCaretaker(); | |
rolestateCaretaker.setMemento(gameRole.saveState()); | |
System.out.println("-----------------------大战boss后-------------------------"); | |
// 损耗 | |
gameRole.fight(); | |
gameRole.stateDisplay(); | |
System.out.println("-----------------------恢复之前的状态-----------------------"); | |
gameRole.recoverState(rolestateCaretaker.getMemento()); | |
// 展示状态 | |
gameRole.stateDisplay(); | |
} | |
} |
# 解释器模式 (Interpreter Pattern)
- 定义一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
# 代码案例
/** | |
* 抽象表达式类 | |
*/ | |
public abstract class AbstractExpression { | |
/** | |
* 解释器抽象方法 | |
* @param context 环境 | |
* @return int | |
*/ | |
public abstract int interpret(Context context); | |
} |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* 环境角色类 | |
*/ | |
public class Context { | |
/** | |
* 定义一个 Map 集合,用来储存变量以及对应的值 | |
*/ | |
private Map<Variable, Integer> map = new HashMap<>(); | |
/** | |
* 添加变量 | |
*/ | |
public void assign(Variable var, Integer value) { | |
map.put(var, value); | |
} | |
/** | |
* 根据变量获取对应的值 | |
*/ | |
public int getValue(Variable var) { | |
return map.get(var); | |
} | |
} |
/** | |
* 减法表达式类 | |
*/ | |
public class Minus extends AbstractExpression { | |
/** | |
* 减号左边的表达式 | |
*/ | |
private AbstractExpression left; | |
/** | |
* 减号右边的表达式 | |
*/ | |
private AbstractExpression right; | |
public Minus(AbstractExpression left, AbstractExpression right) { | |
this.left = left; | |
this.right = right; | |
} | |
@Override | |
public int interpret(Context context) { | |
// 将左边表达式的结果和右边表达式的结果相减 | |
return left.interpret(context) - right.interpret(context); | |
} | |
@Override | |
public String toString() { | |
return String.format("(%s - %s)", left.toString(), right.toString()); | |
} | |
} |
/** | |
* 加法表达式类 | |
*/ | |
public class Plus extends AbstractExpression { | |
/** | |
* 加号左边的表达式 | |
*/ | |
private AbstractExpression left; | |
/** | |
* 加号右边的表达式 | |
*/ | |
private AbstractExpression right; | |
public Plus(AbstractExpression left, AbstractExpression right) { | |
this.left = left; | |
this.right = right; | |
} | |
@Override | |
public int interpret(Context context) { | |
// 将左边表达式的结果和右边表达式的结果相加 | |
return left.interpret(context) + right.interpret(context); | |
} | |
@Override | |
public String toString() { | |
return String.format("(%s + %s)", left.toString(), right.toString()); | |
} | |
} |
/** | |
* 封装变量的类 | |
*/ | |
public class Variable extends AbstractExpression { | |
/** | |
* 声明储存变量名的变量 | |
*/ | |
private String name; | |
public Variable(String name) { | |
this.name = name; | |
} | |
@Override | |
public int interpret(Context context) { | |
// 直接返回变量的值 | |
return context.getValue(this); | |
} | |
@Override | |
public String toString() { | |
return name; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建环境 | |
Context context = new Context(); | |
// 创建多个变量 | |
Variable a = new Variable("a"); | |
Variable b = new Variable("b"); | |
Variable c = new Variable("c"); | |
Variable d = new Variable("d"); | |
context.assign(a, 1); | |
context.assign(b, 2); | |
context.assign(c, 3); | |
context.assign(d, 4); | |
// 获取抽象语法数 | |
AbstractExpression expression = new Minus(a, new Plus(new Minus(b, c), d)); | |
// 解释 | |
int interpret = expression.interpret(context); | |
System.out.println(expression + "=" + interpret); | |
} | |
} |
# 状态模式 (State Pattern)
- 允许一个对象在其内部状态改变时改变它的行为。
- 对象看起来似乎修改了它所属的类。
# 代码案例
# after
/** | |
* @author LightRain | |
* 抽象状态类 | |
*/ | |
public abstract class LifeState { | |
/** | |
* 声明环境变量 | |
*/ | |
protected Context context; | |
public void setContext(Context context) { | |
this.context = context; | |
} | |
/** | |
* 电梯开启操作 | |
*/ | |
public abstract void open(); | |
/** | |
* 电梯关闭操作 | |
*/ | |
public abstract void close(); | |
/** | |
* 电梯运行操作 | |
*/ | |
public abstract void run(); | |
/** | |
* 电梯停止操作 | |
*/ | |
public abstract void stop(); | |
} |
/** | |
* @author LightRain | |
* 环境角色类 | |
*/ | |
public class Context { | |
/** | |
* 定义对应状态对象的常量 | |
*/ | |
public final static OpeningState OPENING_STATE = new OpeningState(); | |
public final static CloseingState CLOSEING_STATE = new CloseingState(); | |
public final static RuningState RUNING_STATE = new RuningState(); | |
public final static StopingState STOPPING_STATE = new StopingState(); | |
/** | |
* 定义当前电梯状态变量 | |
*/ | |
private LifeState lifeState; | |
public LifeState getLifeState() { | |
return lifeState; | |
} | |
/** | |
* 设置当前状态 | |
* | |
* @param lifeState LifeState | |
*/ | |
public void setLifeState(LifeState lifeState) { | |
this.lifeState = lifeState; | |
// 设置当前状态对象中的 Context 对象 | |
this.lifeState.setContext(this); | |
} | |
public void open() { | |
this.lifeState.open(); | |
} | |
public void close() { | |
this.lifeState.close(); | |
} | |
public void run() { | |
this.lifeState.run(); | |
} | |
public void stop() { | |
this.lifeState.stop(); | |
} | |
} |
/** | |
* @author LightRain | |
* 电梯关闭状态类 | |
*/ | |
public class CloseingState extends LifeState { | |
/** | |
* 电梯门关闭,这是关闭状态要实现的动作 | |
*/ | |
@Override | |
public void open() { | |
super.context.setLifeState(Context.OPENING_STATE); | |
super.context.open(); | |
} | |
/** | |
* 电梯门关了再打开,逗你玩呢,那这个允许呀 | |
*/ | |
@Override | |
public void close() { | |
System.out.println("电梯门关闭..."); | |
} | |
/** | |
* 电梯门关了就跑,这是再正常不过了 | |
*/ | |
@Override | |
public void run() { | |
super.context.setLifeState(Context.RUNING_STATE); | |
super.context.run(); | |
} | |
/** | |
* 电梯门关着,我就不按楼层 | |
*/ | |
@Override | |
public void stop() { | |
super.context.setLifeState(Context.STOPPING_STATE); | |
super.context.stop(); | |
} | |
} |
/** | |
* @author LightRain | |
* 电梯开启状态类 | |
*/ | |
public class OpeningState extends LifeState { | |
@Override | |
public void open() { | |
System.out.println("电梯开启..."); | |
} | |
@Override | |
public void close() { | |
// 修改状态 | |
super.context.setLifeState(Context.CLOSEING_STATE); | |
// 调用当前状态中的 Context 中的 close 方法 | |
super.context.close(); | |
} | |
@Override | |
public void run() { | |
} | |
@Override | |
public void stop() { | |
} | |
} |
/** | |
* @author LightRain | |
* 电梯运行状态类 | |
*/ | |
public class RuningState extends LifeState { | |
/** | |
* 运行的时候开电梯门?你疯了!电梯不会给你开的 | |
*/ | |
@Override | |
public void open() { | |
//do nothing | |
} | |
/** | |
* 电梯门关闭?这是肯定了 | |
*/ | |
@Override | |
public void close() { | |
// 虽然可以关门,但这个动作不归我执行 | |
// do nothing | |
} | |
/** | |
* 这是在运行状态下要实现的方法 | |
*/ | |
@Override | |
public void run() { | |
System.out.println("电梯正在运行..."); | |
} | |
/** | |
* 这个事绝对是合理的,光运行不停止还有谁坐电梯 | |
*/ | |
public void stop() { | |
super.context.setLifeState(Context.STOPPING_STATE); | |
super.context.stop(); | |
} | |
} |
/** | |
* @author LightRain | |
* 电梯停止状态类 | |
*/ | |
public class StopingState extends LifeState { | |
/** | |
* 停止状态,开门,那是要的! | |
*/ | |
@Override | |
public void open() { | |
// 状态修改 | |
super.context.setLifeState(Context.OPENING_STATE); | |
// 动作委托为 CloseState 来执行,也就是委托给了 ClosingState 子类执行这个动作 | |
super.context.open(); | |
} | |
@Override | |
public void close() { | |
// 虽然可以关门,但这个动作不归我执行 | |
// 状态修改 | |
super.context.setLifeState(Context.CLOSEING_STATE); | |
// 动作委托为 CloseState 来执行,也就是委托给了 ClosingState 子类执行这个动作 | |
super.context.close(); | |
} | |
/** | |
* 停止状态再跑起来,正常的很 | |
*/ | |
@Override | |
public void run() { | |
// 状态修改 | |
super.context.setLifeState(Context.RUNING_STATE); | |
// 动作委托为 CloseState 来执行,也就是委托给了 ClosingState 子类执行这个动作 | |
super.context.run(); | |
} | |
/** | |
* 停止状态是怎么发生的呢?当然是停止方法执行了 | |
*/ | |
@Override | |
public void stop() { | |
System.out.println("电梯停止了... "); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建电梯对象 | |
Context context = new Context(); | |
// 设置电梯状态 | |
context.setLifeState(new RuningState()); | |
context.open(); | |
context.close(); | |
context.run(); | |
context.stop(); | |
} | |
} |
# before
/** | |
* @author LightRain | |
* 电梯接口 | |
*/ | |
public interface ILift { | |
/** | |
* 定义四个电梯状态的常量 | |
*/ | |
int OPENING_STATE = 1; | |
int CLOSED_STATE = 2; | |
int RUNNING_STATE = 3; | |
int STOPPED_STATE = 4; | |
/** | |
* 设置电梯状态 | |
* | |
* @param state int | |
*/ | |
void setState(int state); | |
/** | |
* 电梯操作功能 | |
*/ | |
void open(); | |
void close(); | |
void run(); | |
void stop(); | |
} |
public class Lift implements ILift { | |
/** | |
* 记录电梯状态 | |
*/ | |
private int state; | |
@Override | |
public void setState(int state) { | |
this.state = state; | |
} | |
@Override | |
public void open() { | |
switch (state) { | |
case OPENING_STATE -> { | |
} | |
case CLOSED_STATE -> { | |
System.out.println("电梯打开了"); | |
// 设置当前电梯状态 | |
setState(OPENING_STATE); | |
} | |
case STOPPED_STATE -> { | |
System.out.println("电梯打开了"); | |
// 设置当前电梯状态 | |
setState(OPENING_STATE); | |
} | |
case RUNNING_STATE -> { | |
} | |
} | |
} | |
@Override | |
public void close() { | |
switch (state) { | |
case OPENING_STATE -> { | |
System.out.println("电梯关门了..."); | |
// 关门之后就是关闭状态 | |
setState(CLOSED_STATE); | |
} | |
case CLOSED_STATE -> { | |
//do nothing 已经是关门状态,不能关门 | |
} | |
case STOPPED_STATE -> { | |
//do nothing 运行时电梯是关着的,不能关门 | |
} | |
case RUNNING_STATE -> { | |
//do nothing 停止时电梯也是关着的,不能关门 | |
} | |
} | |
} | |
@Override | |
public void run() { | |
switch (state) { | |
case OPENING_STATE -> { | |
//do nothing 电梯不能开着门就走 | |
} | |
case CLOSED_STATE -> { | |
// 门关了可以运行了 | |
System.out.println("电梯开始运行..."); | |
// 修改成运行状态 | |
setState(RUNNING_STATE); | |
} | |
case STOPPED_STATE -> { | |
System.out.println("电梯开始运行了..."); | |
// 修改成运行状态 | |
setState(RUNNING_STATE); | |
} | |
case RUNNING_STATE -> { | |
//do nothing 已经是运行状态了 | |
} | |
} | |
} | |
@Override | |
public void stop() { | |
switch (state) { | |
case OPENING_STATE -> { | |
//do nothing 开门的电梯已经是是停止的了 (正常情况下) | |
} | |
case CLOSED_STATE -> { | |
// 关门时才可以停止 | |
System.out.println("电梯停止了..."); | |
// 修改成运行状态 | |
setState(STOPPED_STATE); | |
} | |
case STOPPED_STATE -> { | |
} | |
case RUNNING_STATE -> { | |
// 运行时可以停止 | |
System.out.println("电梯停止了..."); | |
// 修改成运行状态 | |
setState(STOPPED_STATE); | |
} | |
} | |
} | |
} |
public class Mian { | |
public static void main(String[] args) { | |
// 创建电梯对象 | |
Lift i = new Lift(); | |
// 设置电梯状态 | |
i.setState(ILift.STOPPED_STATE); | |
// 开门 | |
i.open(); | |
// 关门 | |
i.close(); | |
// 运行 | |
i.run(); | |
// 停止 | |
i.stop(); | |
} | |
} |
# 策略模式 (Strategy Pattern)
- 定义一系列的算法,把它们一个个封装起来,并且使他们可相互替换。
- 本模式使得算法的变化可以独立于使用它的客户。
# 代码案例
/** | |
* @author LightRain | |
* 抽象策略角色类 | |
*/ | |
public interface Strategy { | |
void show(); | |
} |
/** | |
* @author LightRain | |
* 具体策略角色类 | |
*/ | |
public class StrategyA implements Strategy { | |
@Override | |
public void show() { | |
System.out.println("买一送一"); | |
} | |
} |
/** | |
* @author LightRain | |
* 具体策略角色类 | |
*/ | |
public class StrategyB implements Strategy { | |
@Override | |
public void show() { | |
System.out.println("满200减50"); | |
} | |
} |
/** | |
* @author LightRain | |
* 具体策略角色类 | |
*/ | |
public class StrategyC implements Strategy { | |
@Override | |
public void show() { | |
System.out.println("满1000减200"); | |
} | |
} |
/** | |
* @author LightRain | |
* 策略模式 / 促销员类 | |
*/ | |
public class SalesMan { | |
/** | |
* 聚合策略接口 | |
*/ | |
private Strategy strategy; | |
/** | |
* 接口式构造器 | |
* | |
* @param strategy 策略接口 | |
*/ | |
public SalesMan(Strategy strategy) { | |
this.strategy = strategy; | |
} | |
/** | |
* 调用方法 | |
*/ | |
public void salesManShow() { | |
strategy.show(); | |
} | |
/** | |
* 提供 set 方法 | |
* | |
* @param strategy 策略接口 | |
*/ | |
public void setStrategy(Strategy strategy) { | |
this.strategy = strategy; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建促销员 | |
SalesMan salesMan = new SalesMan(new StrategyB()); | |
salesMan.salesManShow(); | |
System.out.println("============"); | |
// 使用春节促销活动 | |
salesMan.setStrategy(new StrategyA()); | |
salesMan.salesManShow(); | |
System.out.println("============"); | |
// 使用中秋节活动 | |
salesMan.setStrategy(new StrategyC()); | |
salesMan.salesManShow(); | |
} | |
} |
# 责任链模式 (Chain of Responsibility Pattern)
- 为解除请求的发送者和接收者之间的耦合,而使多个对象都有机会处理这个请求。
- 将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它。
# 代码案例
/** | |
* @author LightRain | |
* 抽象处理者类 | |
*/ | |
public abstract class Handler { | |
protected final static int NUM_ONE = 1; | |
protected final static int NUM_THREE = 3; | |
protected final static int NUM_SEVEN = 7; | |
/** | |
* 该领导处理的请求天数区间 | |
*/ | |
private int numStart; | |
private int numEnd; | |
/** | |
* 声明后继者(声明上级领导) | |
*/ | |
private Handler nextHandler; | |
public Handler(int numStart) { | |
this.numStart = numStart; | |
} | |
public Handler(int numStart, int numEnd) { | |
this.numStart = numStart; | |
this.numEnd = numEnd; | |
} | |
/** | |
* 设置上级领导对象 | |
* | |
* @param nextHandler Handler | |
*/ | |
public void setNextHandler(Handler nextHandler) { | |
this.nextHandler = nextHandler; | |
} | |
/** | |
* 各级领导处理请求条的方法 | |
* | |
* @param leave LeaveRequest | |
*/ | |
protected abstract void handlerLeave(LeaveRequest leave); | |
/** | |
* 提交请求 | |
* | |
* @param leave LeaveRequest | |
*/ | |
public final void submit(LeaveRequest leave) { | |
// 该领导进行审批 | |
if (this.nextHandler != null && leave.getNum() > this.numEnd) { | |
// 提交给上级领导审批 | |
this.nextHandler.submit(leave); | |
} else { | |
if (leave.getNum() >= NUM_ONE && leave.getNum() <= NUM_SEVEN) { | |
this.handlerLeave(leave); | |
} | |
System.out.println("流程结束!"); | |
} | |
} | |
} |
/** | |
* @author LightRain | |
* 小组长类(具体的处理者) | |
*/ | |
public class GroupLeader extends Handler { | |
public GroupLeader() { | |
super(0, NUM_ONE); | |
} | |
@Override | |
protected void handlerLeave(LeaveRequest leave) { | |
System.out.println(leave.getName() + "请假 " + leave.getNum() + "天" + leave.getContent() + "。"); | |
System.out.println("小组长审批:通过"); | |
} | |
} |
/** | |
* @author LightRain | |
* 总经理类(具体的处理者) | |
*/ | |
public class GeneralManager extends Handler { | |
public GeneralManager() { | |
super(NUM_THREE, NUM_SEVEN); | |
} | |
@Override | |
protected void handlerLeave(LeaveRequest leave) { | |
System.out.println(leave.getName() + "请假 " + leave.getNum() + "天" + leave.getContent() + "。"); | |
System.out.println("总经理:通过"); | |
} | |
} |
/** | |
* @author LightRain | |
* 部门经理类(具体的处理者) | |
*/ | |
public class Manager extends Handler { | |
public Manager() { | |
super(NUM_ONE, NUM_THREE); | |
} | |
@Override | |
protected void handlerLeave(LeaveRequest leave) { | |
System.out.println(leave.getName() + "请假 " + leave.getNum() + "天" + leave.getContent() + "。"); | |
System.out.println("部门经理:通过"); | |
} | |
} |
/** | |
* @author LightRain | |
* 请假条类 | |
*/ | |
public class LeaveRequest { | |
/** | |
* 姓名 | |
*/ | |
private String name; | |
/** | |
* 天数 | |
*/ | |
private int num; | |
/** | |
* 内容 | |
*/ | |
private String content; | |
public LeaveRequest(String name, int num, String content) { | |
this.name = name; | |
this.num = num; | |
this.content = content; | |
} | |
public String getName() { | |
return name; | |
} | |
public int getNum() { | |
return num; | |
} | |
public String getContent() { | |
return content; | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建请假条对象 | |
LeaveRequest leave = new LeaveRequest("小明", 4, "感冒"); | |
// 创建各级领导 | |
GroupLeader groupLeader = new GroupLeader(); | |
Manager manager = new Manager(); | |
GeneralManager generalManager = new GeneralManager(); | |
// 设置处理者链 | |
groupLeader.setNextHandler(manager); | |
manager.setNextHandler(generalManager); | |
// 提交 | |
groupLeader.submit(leave); | |
} | |
} |
# 访问者模式 (Visitor Pattern)
- 表示一个作用于某对象结构中的各元素的操作。
- 它使你可以在不改变各元素类别的前提下定义作用于这些元素的新操作。
# 代码案例
/** | |
* @author LightRain | |
* 抽象元素角色类 | |
*/ | |
public interface Animal { | |
/** | |
* 接收访问者访问的功能 | |
* @param person Person | |
*/ | |
void accept(Person person); | |
} |
/** | |
* @author LightRain | |
* 抽象访问者角色类 | |
*/ | |
public interface Person { | |
/** | |
* 喂食宠物猫 | |
* | |
* @param cat Cat | |
*/ | |
void feed(Cat cat); | |
/** | |
* 喂食宠物狗 | |
* | |
* @param dog Dog | |
*/ | |
void feed(Dog dog); | |
} |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* @author LightRain | |
* 对象结构类 | |
*/ | |
public class Home { | |
/** | |
* 声明一个集合对象,用来储存元素对象 | |
*/ | |
private final List<Animal> nodeList = new ArrayList<>(); | |
/** | |
* | |
* @param person | |
*/ | |
public void action(Person person) { | |
// 遍历集合获取每一个元素,让访问者访问每一个元素 | |
for (Animal animal : nodeList) { | |
animal.accept(person); | |
} | |
} | |
/** | |
* 添加元素功能 | |
* @param animal Animal | |
*/ | |
public void add(Animal animal) { | |
nodeList.add(animal); | |
} | |
} |
/** | |
* @author LightRain | |
* 具体元素角色类(宠物猫) | |
*/ | |
public class Cat implements Animal { | |
@Override | |
public void accept(Person person) { | |
// 访问者给宠物猫喂食 | |
person.feed(this); | |
System.out.println("宠物猫"); | |
} | |
} |
/** | |
* @author LightRain | |
* 具体元素角色类(宠物狗) | |
*/ | |
public class Dog implements Animal { | |
@Override | |
public void accept(Person person) { | |
// 访问者给宠物狗喂食 | |
person.feed(this); | |
System.out.println("宠物狗"); | |
} | |
} |
/** | |
* @author LightRain | |
* 具体访问者角色类(宠物主人类) | |
*/ | |
public class Owner implements Person { | |
@Override | |
public void feed(Cat cat) { | |
System.out.println("主人喂食宠物猫..."); | |
} | |
@Override | |
public void feed(Dog dog) { | |
System.out.println("注入喂食宠物狗..."); | |
} | |
} |
/** | |
* @author LightRain | |
* 具体访问者角色类(其他人) | |
*/ | |
public class Someone implements Person { | |
@Override | |
public void feed(Cat cat) { | |
System.out.println("其他人喂食宠物猫..."); | |
} | |
@Override | |
public void feed(Dog dog) { | |
System.out.println("其他人喂食宠物狗..."); | |
} | |
} |
/** | |
* 测试 | |
*/ | |
public class Main { | |
public static void main(String[] args) { | |
// 创建 Home 对象 | |
Home home = new Home(); | |
// 养只猫和狗 | |
home.add(new Cat()); | |
home.add(new Dog()); | |
// 创建主人对象 | |
Owner owner = new Owner(); | |
// 主人喂食 | |
home.action(owner); | |
// 创建访问者 | |
Someone someone = new Someone(); | |
// 访问者喂食 | |
home.action(someone); | |
} | |
} |