创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式

创建型设计模式之:简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式

(一)简单工厂模式

简单工厂模式将对象的实例化过程封装到一个工厂类中,根据输入的条件创建不同类型的对象。

  • 角色划分:
    • 抽象产品:定义产品的接口
    • 具体产品:实现具体的功能
    • 工厂类:定义一个静态的工厂方法,负责根据条件创建产品

我们以支付方式为例实现一个简单工厂模式。

java 复制代码
// 支付接口(抽象产品)
public interface Payment {
    void pay(double amount);
}

// 支付宝支付(具体产品)
public class Alipay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付:" + amount + "元");
    }
}

// 微信支付(具体产品)
public class WechatPay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付:" + amount + "元");
    }
}

// 支付工厂(负责创建具体产品)
public class PaymentFactory {
    // 工厂方法,根据条件创建产品
    public static Payment createPayment(String type) {
        if ("alipay".equalsIgnoreCase(type)) {
            return new Alipay();
        } else if ("wechat".equalsIgnoreCase(type)) {
            return new WechatPay();
        } else {
            throw new IllegalArgumentException("不支持的支付类型");
        }
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 通过工厂创建支付对象,面向接口而不是具体实现编程
        Payment alipay = PaymentFactory.createPayment("alipay");
        alipay.pay(100.0);  // 输出:使用支付宝支付:100.0元

        Payment wechatPay = PaymentFactory.createPayment("wechat");
        wechatPay.pay(200.0);  // 输出:使用微信支付:200.0元
    }
}
  • 优点:

    • 解耦:将对象的创建与使用分离,客户端不需要关心具体实现类
    • 集中管理:新增或修改产品时只需要调整工厂类
  • 缺点:

    • 违反开闭原则:新增或修改产品类需要调整工厂类代码的 if-else 分支

(二)工厂方法模式

工厂方法模式定义工厂接口(声明工厂方法即创建产品的方法)并为每一种具体产品都实现工厂类,将对象的创建过程延迟到子类进行。

  • 角色划分:
    • 抽象产品:定义产品的接口
    • 具体产品:实现具体的功能
    • 抽象工厂:工厂类的抽象层,声明工厂方法但不实现具体逻辑
    • 具体工厂:为每种具体产品实现一个工厂类,实现工厂方法

我们还是沿用前面的支付方式实现工厂方法模式:

java 复制代码
// 支付接口(抽象产品)
public interface Payment {
    void pay(double amount);
}

// 支付宝支付(具体产品)
public class Alipay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付:" + amount + "元");
    }
}

// 微信支付(具体产品)
public class WechatPay implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付:" + amount + "元");
    }
}

// 抽象工厂(只负责声明抽象方法,但不做具体实现)
public interface PaymentFactory {
    Payment createPayment();
}

// 支付宝支付工厂(具体工厂)
public class AlipayFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        return new Alipay();
    }
}

// 微信支付工厂(具体工厂)
public class WechatPayFactory implements PaymentFactory {
    @Override
    public Payment createPayment() {
        return new WechatPay();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 如需增加支付方式,只需要增加对应的具体产品类和具体工厂类,直接修改客户端即可,符合开闭原则
        PaymentFactory paymentFactory = new AlipayFactory();
        Payment payment = paymentFactory.createPayment();
        payment.pay(100.0);  // 输出:使用支付宝支付:100.0元
    }
}
  • 优点:

    • 符合开闭原则:如需增加产品类型,只需要增加对应的具体产品类和具体工厂类

    • 解耦:客户端只需要依赖抽象工厂和抽象产品,不需要关心具体实现

  • 缺点:

    • 类数量增加:每个产品都对应一个工厂类,导致系统规模膨胀

(三)抽象工厂模式

抽象工厂模式并不像工厂方法模式那样,为每一个产品实现具体工厂类,而是为每一个产品族实现具体工厂类,称为平台工厂。

  • 产品体系结构和产品族:

    • 产品体系结构是同一类产品的不同实现

      • 例如:支付接口,以及下面的微信支付、支付宝支付等实现,构成了支付产品体系结构
    • 产品族是同一平台下的不同产品

      • 例如:微信平台,以及下面的微信支付、微信贷款等产品,构成了微信产品族
  • 角色划分:

    • 抽象产品:定义产品的接口
    • 具体产品:实现具体的功能
    • 抽象平台工厂:声明抽象平台下的产品族的工厂方法
    • 具体平台工厂:实现具体平台下的产品族的工厂方法
java 复制代码
// 支付接口
public interface Payment {
    void pay(double amount);
}

// 微信支付
public class WechatPayment implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount + "元");
    }
}

// 支付宝支付
public class AlipayPayment implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount + "元");
    }
}

// 贷款接口
public interface Loan {
    void apply(double amount);
}

// 微信贷款
public class WechatLoan implements Loan {
    @Override
    public void apply(double amount) {
        System.out.println("微信贷款申请:" + amount + "元");
    }
}

// 支付宝贷款
public class AlipayLoan implements Loan {
    @Override
    public void apply(double amount) {
        System.out.println("支付宝贷款申请:" + amount + "元");
    }
}

// 抽象平台工厂,负责创建平台下的一族产品(包括支付产品与贷款产品)
public interface PlatformFactory {
    Payment createPayment();
    Loan createLoan();
}

// 微信平台工厂
public class WechatFactory implements PlatformFactory {
    @Override
    public Payment createPayment() {
        return new WechatPayment();
    }

    @Override
    public Loan createLoan() {
        return new WechatLoan();
    }
}

// 支付宝平台工厂
public class AlipayFactory implements PlatformFactory {
    @Override
    public Payment createPayment() {
        return new AlipayPayment();
    }

    @Override
    public Loan createLoan() {
        return new AlipayLoan();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        PlatformFactory platformFactory = new WechatFactory();
        Payment payment = platformFactory.createPayment();
        Loan loan = platformFactory.createLoan();
        payment.pay(100.0);
        loan.apply(100.0);
    }
} 
  • 开闭原则的倾斜性:
    • 新增产品族,只需要增加对应的具体产品和平台工厂类,不需要改动原有代码,符合开闭原则
    • 新增产品体系结构,需要修改抽象平台工厂和所有的具体平台工厂实现,不符合开闭原则

(四)建造者模式

建造者模式主要用于分步骤构建复杂对象,分离构造过程和表示,并通过链式调用增强可读性,避免客户端构造器参数爆炸。

  • 角色划分:
    • 目标类:私有化构造器,确保只能通过建造者类创建对象,并通过 builder() 方法提供建造者的访问入口
    • 建造者类:目标类的静态内部类,私有化构造器,通过链式方法设置可选参数,并通过 build() 方法最终调用目标类私有构造器生成对象

我们来看如何使用建造者模式构建一个计算机对象:

java 复制代码
public class Computer {
    // 计算机类的属性
    private String cpu;
    private String ram;
    private String hardDisk;
    private String screen;

    // 私有化构造器,并通过传入建造者创建对象,这个构造器将会在建造者的 build() 方法中被调用
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.hardDisk = builder.hardDisk;
        this.screen = builder.screen;
    }

    // 提供建造者的访问入口
    public static Builder builder() {
        return new Builder();
    }

    // 业务方法
    public void show() {
        System.out.println("cpu: " + cpu);
        System.out.println("ram: " + ram);
        System.out.println("hardDisk: " + hardDisk);
        System.out.println("screen: " + screen);
    }

    // 静态内部建造者类,负责通过链式方法构建目标对象
    public static class Builder {
        private String cpu;
        private String ram;
        private String hardDisk;
        private String screen;
        
        // 私有化构造器,这个构造器将会在目标类的 builder() 方法中被调用
        private Builder() {}

        // 通过一系列链式方法设置目标对象的属性,这些方法都会返回构造器对象,用于最后调用 build() 方法
        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder ram(String ram) {
            this.ram = ram;
            return this;
        }

        public Builder hardDisk(String hardDisk) {
            this.hardDisk = hardDisk;
            return this;
        }

        public Builder screen(String screen) {
            this.screen = screen;
            return this;
        }

        // 返回目标对象
        public Computer build() {
            return new Computer(this);
        }
    }
}

public class Client {
    public static void main(String[] args) {
        Computer computer = Computer.builder() // Builder
                .cpu("i7") // Builder
                .ram("16G") // Builder
                .hardDisk("512G") // Builder
                .screen("15.6") // Builder
                .build(); // Computer
        computer.show();
    }
}

(五)原型模式

原型模式通过复制现有对象(原型)生成新对象,而非通过构造函数初始化。

  • 浅拷贝与深拷贝:
    • 浅拷贝:复制对象的值类型字段,引用类型字段共享同一内存地址(默认的 Object.clone() 实现)
    • 深拷贝:递归复制对象的所有字段(包括引用对象),完全独立于原对象,可以通过序列化和反序列化实现
  • 角色划分:
    • 抽象原型:定义原型公有属性和方法,声明抽象方法,并实现 Cloneable 接口,实现浅拷贝或深拷贝逻辑
    • 具体原型:定义具体原型,实现抽象方法
    • 原型管理器:负责通过原型注册表管理原型,并克隆出新对象

假设游戏中需要快速生成大量相似的敌人,但每个敌人的初始状态(位置、装备)可能不同:

java 复制代码
// 抽象原型接口(实现 Cloneable)
public abstract class Enemy implements Cloneable {
    protected String type;
    protected int x;
    protected int y;
    protected List<String> equipment;  // 引用类型字段(测试深拷贝)

    public abstract void attack();

    // 实现浅拷贝(默认)
    @Override
    public Enemy clone() {
        try {
            return (Enemy) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException("克隆失败", e);
        }
    }

    // 深拷贝实现(需手动重写)
    public Enemy deepClone() {
        Enemy cloned = this.clone();
        cloned.equipment = new ArrayList<>(this.equipment);  // 深拷贝引用字段
        return cloned;
    }

    // Setters & Getters
    public void setPosition(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void addEquipment(String item) {
        this.equipment.add(item);
    }
}

// 具体原型:普通敌人
public class NormalEnemy extends Enemy {
    public NormalEnemy() {
        type = "普通敌人";
        equipment = new ArrayList<>(List.of("短剑"));  // 默认装备
    }

    @Override
    public void attack() {
        System.out.printf("[%s] 在位置(%d, %d) 发动攻击,装备:%s\n", 
                          type, x, y, equipment);
    }
}

// 具体原型:Boss敌人
public class BossEnemy extends Enemy {
    public BossEnemy() {
        type = "Boss";
        equipment = new ArrayList<>(List.of("巨斧", "重甲"));
    }

    @Override
    public void attack() {
        System.out.printf("[%s] 在位置(%d, %d) 释放技能,装备:%s\n", 
                          type, x, y, equipment);
    }
}

import java.util.HashMap;
import java.util.Map;

public class EnemyRegistry {
    private static Map<String, Enemy> prototypes = new HashMap<>();

    static {
        // 预注册原型
        prototypes.put("normal", new NormalEnemy());
        prototypes.put("boss", new BossEnemy());
    }

    // 获取克隆对象
    public static Enemy getEnemy(String type) {
        Enemy prototype = prototypes.get(type);
        if (prototype == null) {
            throw new IllegalArgumentException("未知敌人类型");
        }
        return prototype.deepClone();  // 深拷贝返回
    }

    // 动态添加原型
    public static void addPrototype(String key, Enemy enemy) {
        prototypes.put(key, enemy);
    }
}

// 客户端
public class GameClient {
    public static void main(String[] args) {
        // 从注册表克隆敌人
        Enemy enemy1 = EnemyRegistry.getEnemy("normal");
        enemy1.setPosition(10, 20);
        enemy1.addEquipment("盾牌");  // 修改克隆体的装备
        enemy1.attack(); // 输出:[普通敌人] 在位置(10, 20) 发动攻击,装备:[短剑, 盾牌]

        Enemy enemy2 = EnemyRegistry.getEnemy("boss");
        enemy2.setPosition(50, 30);
        enemy2.attack(); // 输出:[Boss] 在位置(50, 30) 释放技能,装备:[巨斧, 重甲]
    }
}
相关推荐
纪元A梦几秒前
华为OD机试真题——绘图机器(2025A卷:100分)Java/python/JavaScript/C++/C/GO最佳实现
java·javascript·c++·python·华为od·go·华为od机试题
24k小善15 分钟前
FlinkSql入门与实践
java·大数据·flink·云计算
CodeCraft Studio28 分钟前
Excel处理控件Spire.XLS系列教程:Java设置Excel活动工作表或活动单元格
java·python·excel
瓯雅爱分享1 小时前
任务管理系统,Java+Vue,含源码与文档,科学规划任务节点,全程督办保障项目落地提效
java·mysql·vue·软件工程·源代码管理
chxii1 小时前
2.3java运算符
java
余辉zmh1 小时前
【Linux系统篇】:信号的生命周期---从触发到保存与捕捉的底层逻辑
android·java·linux
小布不吃竹1 小时前
Maven的概念与初识Maven
java·maven
中东大鹅1 小时前
Maven进阶
java·maven
星星点点洲1 小时前
【设计模式区别】装饰器模式和适配器模式区别
设计模式·适配器模式·装饰器模式
serene941 小时前
IntelliJ IDEA 2025.2 和 JetBrains Rider 2025.1 恢复git commit为模态窗口
java·git·intellij-idea