1.单例模式:
是java中最简单模式之一
特点:单例类只能有一个实例
单例类必须自己创建自己的唯一实例
单例类必须给所有其他对象提供这一实例
(1)饿汉式(比较常用,但容易产生垃圾对象):
优点:没有加锁,执行效率会提高,线程安全,获取实例速度快(提前创建好了,类加载时就创建实例)
缺点:类加载时就初始化,不能延迟加载,浪费内存
适用于:单例对象较小,对内存要求不高的场景
//静态代码块:只执行一次
//线程安全 浪费资源
public class Eager1 {
private Eager1(){ }
private static Eager1 instance;//实例
public static Eager1 getInstance() {//访问点,只能通过getInstance这个方法访问
return instance;
}
//利用静态代码块的特点来完成单例的创建
static{
instance=new Eager1();
}
}
//常量
public class Eager2 {
private static final Eager2 instance=new Eager2();//final
private Eager2(){}
public static Eager2 getInstance()//访问点
{
return instance;
}
}
(2)懒汉式:
是一种延迟初始化的实现方式,只有在第一次使用时才会创建实例。
基础懒汉式:
优点:延迟初始化,第一次调用的时候才创建实例,避免了不必要的资源占用,灵活控制初始化时机,可以在运行时决定是否初始化
缺点:在多线程环境下可能创建多个实例,破坏单例原则
适用场景:适合初始化成本高的对象(数据库连接池、线程池等)
非线程安全:
public class Singleton {
private static Singleton instance;
private Singleton() {} // 私有构造
public static Singleton getInstance() {
if (instance == null) { // 第一次调用时创建
instance = new Singleton(); // 非线程安全!
}
return instance;
}
}
线程安全改进,加锁:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {//synchronized 加锁
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
(3)双重检查锁
结合延迟加载和线程安全,减少同步锁的开销
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) { // 加锁
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}
volaile
关键字禁止指令重排序,避免返回未初始化的实例。两次检查确保线程安全。
优点:线程安全且性能较高
缺点:代码较复杂,需理解内存模型
适合场景:高并发环境
(4)静态内部类
利用类加载机制保证线程安全,同时延迟加载
public class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return Holder.instance;
}
}
原理:内部类holder在getinstance()首次调用时才会加载
优点:线程安全、延迟加载、无锁高性能
缺点:无法防止反射攻击
适用场景:大多数场景
(5)枚举
基于枚举类型的天然单例特性,防止反射和序列化破坏
public enum Singleton {
INSTANCE;
public void doSomething() {
// 业务方法
}
}
优点:线程安全,天然防止反射创建新实例,自动处理序列化和反序列化
缺点:不够灵活(无法继承其他类)
适用场景:需要绝对防止多实例的场景(如配置管理器)
2.原型模式
通过复制现有对象(原型)来创建新对象,而不是通过new
关键字实例化。这种方式特别适用于创建成本较高的对象,或者当系统需要独立于对象创建和构成的方式时。
声明克隆方法的接口
实现克隆方法的具体类
通过复制原型来创建新对象
浅拷贝:
使用 Object.clone() 方法 | 直接调用 super.clone() ,依赖 JVM 的默认浅拷贝行为,复制字段值(包括引用地址)。 |
// 1. 原型接口
interface Prototype extends Cloneable {
Prototype clone();
}
// 2. 具体原型
class ConcretePrototype implements Prototype {
private String field;
private List<String> listField;
public ConcretePrototype(String field, List<String> list) {
this.field = field;
this.listField = list;
}
// 浅拷贝实现
public Prototype clone() {
try {
return (ConcretePrototype)super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
// getters and setters
}
// 3. 客户端使用
public class Client {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("item1");
ConcretePrototype original = new ConcretePrototype("value", list);
ConcretePrototype copy = (ConcretePrototype)original.clone();
System.out.println(original == copy); // false - 不同对象
System.out.println(original.getListField() == copy.getListField()); // true - 共享引用
}
}
深拷贝:
手动创建新对象并复制数据 | 显式通过 new 和构造函数创建新对象,并复制引用类型字段的实际内容。 |
class ConcretePrototype implements Prototype {
private String field;
private List<String> listField;
public ConcretePrototype(String field, List<String> list) {
this.field = field;
this.listField = new ArrayList<>(list); // 防御性复制
}
// 深拷贝实现
public Prototype clone() {
List<String> newList = new ArrayList<>(this.listField);
return new ConcretePrototype(this.field, newList);
}
// getters and setters
}
// 客户端使用
public class Client {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("item1");
ConcretePrototype original = new ConcretePrototype("value", list);
ConcretePrototype copy = (ConcretePrototype)original.clone();
System.out.println(original == copy); // false
System.out.println(original.getListField() == copy.getListField()); // false
}
}
应用场景:对象创建成本高
优点:
性能优化:避免重复初始化操作
灵活性:动态添加和删除产品
简化创建结构:避免复杂的创建层次
保护性拷贝:可以方便地实现防御性编程
缺点:
深拷贝实现复杂:特别是对象包含循环引用时
需要克隆方法:每个类都需要正确实现克隆方法
可能违反封装:需要暴露对象内部细节来实现克隆
简单工厂:
角色:抽象产品(定义产品的接口或抽象类)、具体产品(实现抽象产品的具体类)、工厂类(根据参数创建并返回具体产品的实例)
代码示例:
// 1. 抽象产品:定义接口
interface Shape {
void draw();
}
// 2. 具体产品:实现接口
class Circle implements Shape {
@Override
public void draw() {
System.out.println("绘制圆形");
}
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("绘制矩形");
}
}
// 3. 工厂类:根据参数创建对象
class ShapeFactory {
public Shape createShape(String type) {
if ("circle".equalsIgnoreCase(type)) {
return new Circle();
} else if ("rectangle".equalsIgnoreCase(type)) {
return new Rectangle();
}
throw new IllegalArgumentException("未知图形类型: " + type);
}
}
// 4. 客户端使用
public class Client {
public static void main(String[] args) {
ShapeFactory factory = new ShapeFactory();
Shape shape = factory.createShape("circle");
shape.draw(); // 输出:绘制圆形
}
}
缺点与局限
-
违反开闭原则(OCP)
新增产品类型(如Triangle
)需修改工厂类的createShape()
方法。 -
工厂类职责过重
所有产品的创建逻辑集中在一个类中,可能导致代码臃肿。
适用于产品类型固定、无需频繁扩展的场景。尽管其 违反开闭原则,但在小型项目或快速开发中仍具有实用价值。对于复杂系统,建议结合工厂方法或抽象工厂模式提升扩展性。
3.工厂方法:
核心思想是 将对象的创建延迟到子类。通过定义一个创建对象的接口,但让子类决定具体实例化哪个类,实现 对象创建与使用的解耦,符合开闭原则(对扩展开放,对修改关闭)。
角色:抽象产品(定义产品的接口或抽象类)、具体产品(实现抽象产品的具体类)、抽象工厂(声明工厂方法,返回抽象产品类型)、具体工厂(实现工厂方法,生成具体产品)
代码示例:
// 1. 抽象产品
interface Document {
void open();
void save();
}
// 2. 具体产品
class WordDocument implements Document {
@Override
public void open() { System.out.println("打开Word文档"); }
@Override
public void save() { System.out.println("保存Word文档"); }
}
class PDFDocument implements Document {
@Override
public void open() { System.out.println("打开PDF文档"); }
@Override
public void save() { System.out.println("保存PDF文档"); }
}
// 3. 抽象工厂
interface DocumentFactory {
Document createDocument();
}
// 4. 具体工厂
class WordFactory implements DocumentFactory {
@Override
public Document createDocument() {
return new WordDocument();
}
}
class PDFFactory implements DocumentFactory {
@Override
public Document createDocument() {
return new PDFDocument();
}
}
// 5. 客户端使用
public class Client {
public static void main(String[] args) {
DocumentFactory factory = new WordFactory();
Document doc = factory.createDocument();
doc.open(); // 输出:打开Word文档
}
}
核心优点
-
符合开闭原则
新增产品类型时,只需添加对应的具体工厂和产品类,无需修改已有代码。 -
解耦客户端与具体类
客户端仅依赖抽象接口(Document
和DocumentFactory
),不直接耦合具体实现。 -
支持多态性
工厂方法可返回不同子类对象,实现灵活的对象创建逻辑。
缺点
-
类数量膨胀
每个产品需对应一个工厂类,增加系统复杂度。 -
抽象性要求高
需要预先设计抽象层,对简单场景可能过度设计。
适用场景
-
对象类型不确定:需运行时动态决定创建哪种对象(如配置文件驱动)。
-
扩展性强:预期系统需频繁新增产品类型(如插件系统)。
-
框架设计:允许用户自定义组件(如Spring的BeanFactory)。
4.抽象工厂
模式定义
抽象工厂模式是一种创建型设计模式,提供 创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。其核心是 围绕产品族(一组有逻辑关联的产品)进行对象创建,确保同一族的产品能协同工作。
核心结构
抽象工厂模式包含以下角色:
-
抽象工厂(Abstract Factory)
定义创建一系列产品对象的接口(如createButton()
,createCheckbox()
)。 -
具体工厂(Concrete Factory)
实现抽象工厂接口,生产同一产品族的对象(如WindowsFactory
生产Windows风格组件)。 -
抽象产品(Abstract Product)
定义一类产品的接口(如Button
、Checkbox
)。 -
具体产品(Concrete Product)
实现抽象产品接口的具体类(如WindowsButton
、MacCheckbox
)。
代码示例
步骤1:定义抽象产品
// 按钮抽象接口
interface Button {
void render();
}
// 复选框抽象接口
interface Checkbox {
void check();
}
步骤2:定义具体产品
// Windows风格按钮
class WindowsButton implements Button {
@Override
public void render() {
System.out.println("渲染一个Windows风格按钮");
}
}
// Mac风格按钮
class MacButton implements Button {
@Override
public void render() {
System.out.println("渲染一个Mac风格按钮");
}
}
// Windows风格复选框
class WindowsCheckbox implements Checkbox {
@Override
public void check() {
System.out.println("勾选Windows风格复选框");
}
}
// Mac风格复选框
class MacCheckbox implements Checkbox {
@Override
public void check() {
System.out.println("勾选Mac风格复选框");
}
}
步骤3:定义抽象工厂
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
步骤4:实现具体工厂
// Windows工厂生产同一族产品
class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
// Mac工厂生产同一族产品
class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
步骤5:客户端使用
public class Application {
private Button button;
private Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
public void renderUI() {
button.render();
checkbox.check();
}
public static void main(String[] args) {
// 根据配置选择工厂
GUIFactory factory;
String osType = System.getProperty("os.name").toLowerCase();
if (osType.contains("windows")) {
factory = new WindowsFactory();
} else {
factory = new MacFactory();
}
Application app = new Application(factory);
app.renderUI();
}
}
模式优势
强产品族一致性:确保同一工厂创建的对象兼容(如所有组件风格统一)。
客户端与具体类解耦:客户端仅依赖抽象接口,不关心具体实现。
易于切换产品族:通过替换工厂实例,可快速切换整套产品(如从Windows主题切换为Mac主题)。
模式缺点
新增产品困难:若需在已有产品族中增加新产品(如新增RadioButton
),需修改所有工厂接口和实现类,违反开闭原则。
类数量膨胀:每新增一个产品族,需新增多个具体产品类和工厂类
适用场景
-
跨平台UI开发
不同操作系统的按钮、菜单、对话框需要风格一致。 -
数据库兼容
支持多种数据库(MySQL、Oracle),同一族产品包括Connection、Statement、ResultSet。 -
游戏引擎
为不同画质等级(低、中、高)创建配套的模型、贴图、特效。
对比工厂方法模式
维度 | 工厂方法模式 | 抽象工厂模式 |
---|---|---|
核心目标 | 创建单一产品 | 创建相关产品族 |
扩展方向 | 新增产品类型(垂直扩展) | 新增产品族(水平扩展) |
代码复杂度 | 较低(一个工厂对应一个产品) | 较高(一个工厂对应多个产品) |
典型场景 | 支付方式(支付宝、微信) | 跨平台UI组件、数据库驱动兼容 |
总结
抽象工厂模式是 管理复杂对象创建 的利器,尤其适合需要保证多对象协同工作的场景。尽管存在扩展性限制,但在产品族明确且稳定的系统中,它能显著提升代码的可维护性和灵活性。
5.创建者模式
模式定义
建造者模式是一种 创建型设计模式,用于 分步骤构建复杂对象。它通过将对象的构造过程与表示分离,使得 相同的构建过程可以创建不同的对象形式。
核心价值:
简化多参数对象的创建(尤其当参数可选或存在依赖时)。
提高代码可读性(链式调用更直观)。
支持构造过程的精细化控制(如必填字段校验)。
核心结构
建造者模式通常包含以下角色:
-
产品(Product)
最终要构建的复杂对象(如Computer
)。 -
抽象建造者(Builder)
定义构造产品的通用步骤接口(如setCPU()
、setRAM()
)。 -
具体建造者(Concrete Builder)
实现抽象建造者接口,提供具体的构造逻辑。 -
指挥者(Director,可选)
控制构造流程(如定义标准化的组装步骤)。
代码示例:自定义电脑配置
步骤1:定义产品类
public class Computer {
private String cpu; // 必填
private String ram; // 必填
private String ssd; // 可选
private String gpu; // 可选
public Computer(String cpu, String ram, String ssd, String gpu) {
this.cpu = cpu;
this.ram = ram;
this.ssd = ssd;
this.gpu = gpu;
}
// 省略Getter方法...
}
步骤2:定义建造者接口
public interface ComputerBuilder {
ComputerBuilder setCPU(String cpu); // 必填
ComputerBuilder setRAM(String ram); // 必填
ComputerBuilder setSSD(String ssd); // 可选
ComputerBuilder setGPU(String gpu); // 可选
Computer build(); // 最终构建方法
}
步骤3:实现具体建造者
public class StandardComputerBuilder implements ComputerBuilder {
private String cpu;
private String ram;
private String ssd;
private String gpu;
@Override
public ComputerBuilder setCPU(String cpu) {
this.cpu = cpu;
return this;
}
@Override
public ComputerBuilder setRAM(String ram) {
this.ram = ram;
return this;
}
@Override
public ComputerBuilder setSSD(String ssd) {
this.ssd = ssd;
return this;
}
@Override
public ComputerBuilder setGPU(String gpu) {
this.gpu = gpu;
return this;
}
@Override
public Computer build() {
// 校验必填参数
if (cpu == null || ram == null) {
throw new IllegalArgumentException("CPU和RAM是必填参数");
}
return new Computer(cpu, ram, ssd, gpu);
}
}
步骤4:客户端使用
public class Client {
public static void main(String[] args) {
Computer gamingPC = new StandardComputerBuilder()
.setCPU("Intel i9") // 链式调用
.setRAM("32GB")
.setGPU("RTX 4090")
.build();
Computer officePC = new StandardComputerBuilder()
.setCPU("Intel i5")
.setRAM("8GB")
.setSSD("512GB")
.build();
}
}
模式优势
参数灵活:可选参数无需传递null
,避免构造方法爆炸。
代码可读性高:链式调用清晰表达参数含义(如 .setCPU("i7")
)。
构造过程可控:支持参数校验、分步构建(如先设置必填项,再添加可选项)。
适用场景
-
复杂对象的创建
对象包含多个部件(如订单包含商品、用户、地址等)。 -
参数存在依赖关系
例如,选择“高性能模式”时自动启用特定配置。 -
不可变对象的构建
通过建造者一次性设置所有参数,避免对象状态中途修改。
总结
建造者模式是处理 多参数对象创建 的最佳实践,尤其适合以下场景:
参数存在大量可选或依赖关系。
需要提高代码可读性和可维护性。
希望支持灵活的构造过程(如参数校验、分步构建)。
通过链式调用和分离构造逻辑,它能显著简化复杂对象的创建,是Java开发者工具箱中的必备设计模式。