设计模式概述
软件设计模式,来源于建筑设计
1995年 GOF(四个人的缩写)合作出版了《设计模式:可复用面向对象软件的基础》一书,书中收录了23个设计模式
设计模式分类
- 创建型模式
用于描述怎么创建对象,将对象的创建和使用分立。
单例、原型、工厂方法、抽象工厂、建造者等5种 - 结构型模式
用于描述怎么将类或对象按照某种布局组成更大的结构
代理、适配器、桥接、装饰、外观、享元、组合等7种 - 行为型模式
用于描述类和对象之间怎么相互协作完成单个对象无法单独完成的任务
模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等11种
UML
统一建模语言
类图表示法
类与类之间的关系
- 关联关系
- 聚合关系
3. 组合关系
整体对象可以控制部分对象的生命周期,整体不存在,部分对象也将不存在
4. 依赖关系
对象之间耦合度最弱的关联方式,某个类调用另一个类
5. 继承关系
耦合度最大的关系
6. 实现关系
软件设计原则
- 开闭原则
程序需要拓展时,不能修改原有的代码 - 里式代换原则
任何基类可以出现的地方,子类一定可以出现。子类可以扩展父类的功能,但不仅能改变父类原有的功能 - 依赖倒转原则
高层模块不能依赖于低层模块
- 接口隔离原则
5. 迪米特法则
又叫最少知识原则。只和你的朋友交谈,不和陌生人交谈
6. 合成复用原则
尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现
创建者模式
单例设计模式
单例类,只能创建一个实例的类
单例设计模式分类两种:
- 饿汉式,类加载时候创建。 会造成内存浪费,如果只创建不调用
- 懒汉式,首次使用该对象才创建。 可能存在线程安全问题,双重检查锁方式(也不是完美的,要加volatile,保证有序性)
破坏单例模式
1、序列化反序列化会破坏单例模式,从文件中读取相当于重新创建了一个(除非是枚举类单例)
解决:添加readResolve方法,当进行反序列化时候,自动调用该方法,返回该方法的返回值
2、反射也会破坏单例模式,通过class文件创建
在类中加一个flag,判断flag来决定是否创建
工厂模式
以咖啡店为例,咖啡店根据不同的咖啡种类,返回不同的咖啡
简单工厂模式
引入咖啡工厂类,咖啡店调用咖啡工厂。不再依赖于具体的咖啡对象。
增加新产品时,还是要修改工厂类的代码,违背了 “开闭原则”
静态工厂模式:把这个工厂变成静态的
工厂方法模式
想喝什么咖啡,就创建什么类型的咖啡工厂
优点:无须对原工厂进行任何修改(而是增加工厂),满足开闭原则
缺点:每增加一种咖啡就增加一种工厂,增加系统复杂度
抽象工厂模式
如果产品多起来,美式咖啡、拿铁咖啡、提拉米苏、抹茶蛋糕。。。用工厂方法模式就太多了。
可以使用抽象工厂模式。
同产品族:同一个工厂生产的产品,如苹果手机、苹果电脑
同产品等级:同一类产品,不同工厂生产的
很抽象
优点:当一个产品族中的多个对象被设计成一起工作时,保证客户端始终只使用同一个产品族的对象
缺点:当产品族中新增一个产品时,所有工厂都需要改变
原型模式
用一个已经创建的实例作为原型,通过复制该原型对象创建一个和原型对象相同的新对象
当创建对象的成本较高时,需要频繁创建相似对象时。使用原型模式可以减少资源消耗和提升效率
// 原型接口
public interface Prototype {
Prototype clone();
}
// 具体原型类
public class ConcretePrototype implements Prototype {
private String field;
public ConcretePrototype(String field) {
this.field = field;
}
@Override
public Prototype clone() {
return new ConcretePrototype(this.field);
}
// Getter 和 Setter
}
// 客户端
public class Client {
public static void main(String[] args) {
ConcretePrototype prototype = new ConcretePrototype("Hello");
ConcretePrototype clone = (ConcretePrototype) prototype.clone();
System.out.println(clone.getField()); // 输出: Hello
}
}
建造者模式
适用于对象的参数过多,实例化时比较麻烦的时候
注重部件构建的过程。而工厂方法模式,注重对象的创建方式,一步到位。
// 产品类:复杂对象
public class House {
private String foundation;
private String structure;
private String roof;
private int rooms;
// 私有构造方法,通过 Builder 创建
private House(HouseBuilder builder) {
this.foundation = builder.foundation;
this.structure = builder.structure;
this.roof = builder.roof;
this.rooms = builder.rooms;
}
@Override
public String toString() {
return "House [Foundation=" + foundation + ", Structure=" + structure + ", Roof=" + roof + ", Rooms=" + rooms + "]";
}
// Builder 类:负责逐步创建 House 对象
public static class HouseBuilder {
private String foundation;
private String structure;
private String roof;
private int rooms;
public HouseBuilder buildFoundation(String foundation) {
this.foundation = foundation;
return this; // 链式调用
}
public HouseBuilder buildStructure(String structure) {
this.structure = structure;
return this;
}
public HouseBuilder buildRoof(String roof) {
this.roof = roof;
return this;
}
public HouseBuilder buildRooms(int rooms) {
this.rooms = rooms;
return this;
}
public House build() {
return new House(this); // 返回最终的复杂对象
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
House house = new House.HouseBuilder()
.buildFoundation("Concrete")
.buildStructure("Wooden")
.buildRoof("Shingles")
.buildRooms(3)
.build();
System.out.println(house);
}
}
代理模式
静态代理
避免与目标对象直接接触。并且代理对象还能对方法进行增强
// 抽象主题
public interface Subject {
void request();
}
// 真实主题
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 代理类
public class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject(); // 延迟初始化
}
System.out.println("Proxy: Additional logic before delegating the request.");
realSubject.request(); // 委托给真实主题
System.out.println("Proxy: Additional logic after delegating the request.");
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Subject proxy = new Proxy();
proxy.request(); // 客户端通过代理对象来访问真实对象
}
}