Java23种设计模式(二):原型模式

Java 中的 23 种设计模式详解

设计模式是软件开发中的最佳实践,帮助开发者在面对复杂设计问题时提供有效的解决方案。GoF(Gang of Four)在其经典著作《设计模式:可复用面向对象软件的基础》中定义了 23 种设计模式。。本文将详细介绍23种经典设计模式,包括创建型模式、结构型模式和行为型模式,提供每种模式的定义、原理、优点、Java示例代码以及详细注释。

目的范围名称描述
创建型(Creational)对象单例模式(Singleton)保证一个类仅有一个实例:并提供一个访问它的全局访问点。
原型模式(Prototype)用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
建造者模式(Builder)将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
抽象工厂模式(Abstract Factory)提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
工厂方法模式(Factory Method)定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method使个类的实例化延迟到其子类。
结构型(Structural)对象适配器模式(Adapter)将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
桥接模式(Bridge)将抽象部分与它的实现部分分离,使它们都可以独立地变化。
组合模式(Composite)将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。
装饰模式(Decorator)动态地给一个对象添加一些额外的职责。就扩展功能而言,Decorator模式比生成子类方式更为灵活。
外观模式(Facade)运用共享技术有效地支持大量细粒度的对象。
享元模式(Flyweight)为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
代理模式(Proxy)为其他对象提供一个代理以控制对这个对象的访问。
适配器模式(Adapter)将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
行为型(Behavioral)对象责任链模式(Chain of Responsibility)为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
命令模式(Command)将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。
迭代器模式(lterator)提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。
中介者模式(Mediator)用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
备志录模式(Memento)在不破坏封装性的前提下,捕获一个对象的内部状态。
观察者模式(Observer)定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
状态模式(State)允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。
策略模式(Strategy)定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。
访问者模式(Visitor)表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
解释器模式(Interpreter)给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
模板方法模式(Template Method)定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Iethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步。

创建型模式(Creational Patterns)

创建型模式关注于对象的创建,提供了更灵活的对象创建方式。

创建型模式分为单例模式(Singleton Pattern)、原型模式(Prototype Pattern)、建造者模式(Builder Pattern)、工厂方法模式(Factory Method Pattern)、抽象工厂模式(Abstract Factory Pattern)

原型模式(Prototype Pattern)

问题

在某些情况下,需要创建对象的副本,但复制一个对象的成本可能很高,或者希望避免与对象的具体类耦合。例如,当创建对象的过程较为复杂,或者对象包含大量共享的状态时,使用常规的创建方法可能会导致性能下降。

解决方案

原型模式的解决方案是通过复制现有对象来创建新对象,而不是从头开始构建。这允许我们以更高效的方式创建新对象,同时避免了与对象类的直接耦合。核心概念是在原型对象的基础上进行克隆,使得新对象具有与原型相同的初始状态。

在原型模式中,通常会有以下几个角色:

  • 抽象原型(Prototype):声明克隆方法,作为所有具体原型的基类或接口。
  • 具体原型(Concrete Prototype):实现克隆方法,从自身创建一个副本。
  • 客户端(Client):使用原型对象的客户端代码,在需要新对象时通过克隆现有对象来创建新实例。

效果

原型模式的应用可以带来以下效果:

  • 减少对象创建的成本:避免了复杂对象的重复初始化过程,提高了创建对象的效率。
  • 避免与具体类耦合:客户端可以通过克隆方法创建新对象,而无需知道具体类的细节,降低了耦合度。
  • 灵活性增加:可以在运行时动态地添加或删除原型,适应不同的对象创建需求。
  • 支持动态配置:可以通过克隆来定制对象的不同配置,而无需修改其代码。

然而,也需要注意一些限制,如:

  • 深克隆问题:原型模式默认进行浅克隆,即复制对象本身和其引用。如果对象内部包含其他对象的引用,可能需要实现深克隆来复制整个对象结构。
  • 克隆方法的实现:某些对象可能不容易进行克隆,特别是涉及到文件、网络连接等资源的情况。

总之,原型模式是一种在需要创建对象副本时非常有用的设计模式,它提供了一种灵活且高效的方法来处理对象的复制需求。

常见的原型模式实现方式有:Cloneable接口(浅拷贝)、序列化(深拷贝)、手动复制(构造器/工厂方法)等。

Cloneable接口实现(浅拷贝)
  • 原理‌:
    • 实现Cloneable标记接口
    • 重写Object.clone()方法
    • 默认实现是浅拷贝(只复制基本类型和引用地址)
  • 优点‌:

    • 实现简单,Java原生支持
    • 性能较高,直接内存复制
  • 缺点‌:

    • 只实现浅拷贝,引用对象共享
    • 需要处理CloneNotSupportedException
    • 无法与单例模式组合使用

Java示例

class CloneablePrototype implements Cloneable {
    private String name;
    private List<String> items = new ArrayList<>();
    
    public CloneablePrototype (String name) {
        this.name = name;
        System.out.println("执行耗时初始化...");
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
    }
    
    @Override
    public CloneablePrototype clone() throws CloneNotSupportedException {
        return (CloneablePrototype) super.clone(); // 浅拷贝
    }
    
    public void addItem(String item) { items.add(item); }
    
    public void printStatus() {
        System.out.println(name + " - Items: " + items + 
                         " (Hash: " + System.identityHashCode(items) + ")");
    }
}


public class PrototypeDemo {

    public static void main(String[] args) throws Exception {
        System.out.println("=== Cloneable实现(浅拷贝) ===");
        CloneablePrototype original1 = new CloneablePrototype("Original1");
        original1.addItem("Item1");
        CloneablePrototype copy1 = original1.clone();
        copy1.addItem("Item2");
        original1.printStatus();
        copy1.printStatus();
    }
}
序列化实现(深拷贝)
  • 原理‌:
    • 通过对象序列化和反序列化实现完全独立的副本
    • 需要实现Serializable接口
    • 所有引用对象也必须可序列化
  • 优点‌:

    • 实现真正的深拷贝
    • 不依赖clone()方法
    • 可以处理复杂对象图
  • 缺点‌:

    • 性能开销较大
    • 所有相关类必须实现Serializable
    • 无法复制不可序列化的对象

Java示例

class SerializablePrototype implements Serializable {
    private static final long serialVersionUID = 1L;
    private String data;
    private List<String> values = new ArrayList<>();
    
    public SerializablePrototype deepCopy() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (SerializablePrototype) ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException("Deep copy failed", e);
        }
    }
    
    public void addValue(String value) { values.add(value); }
    
    public void printStatus() {
        System.out.println(data + " - Values: " + values + 
                         " (Hash: " + System.identityHashCode(values) + ")");
    }
}



public class PrototypeDemo {
    public static void main(String[] args) throws Exception {
        System.out.println("\n=== 序列化实现(深拷贝) ===");
        SerializablePrototype original2 = new SerializablePrototype();
        original2.addValue("Value1");
        SerializablePrototype copy2 = original2.deepCopy();
        copy2.addValue("Value2");
        original2.printStatus();
        copy2.printStatus();
    }
}
手动复制实现(构造器/工厂方法)
  • 原理‌:
    • 通过自定义复制逻辑创建新对象
    • 可以使用构造器或静态工厂方法
    • 完全控制复制过程
  • 优点‌:

    • 完全控制复制过程
    • 不需要实现特殊接口
    • 可以处理任何复杂情况
  • 缺点‌:

    • 需要为每个类编写复制逻辑
    • 维护成本较高
    • 当类结构变化时需要更新复制逻辑

Java示例

class ManualCopyPrototype {
    private String id;
    private List<String> elements = new ArrayList<>();
    
    // 原始构造器
    public ManualCopyPrototype(String id) {
        this.id = id;
        System.out.println("执行复杂初始化...");
        try { Thread.sleep(1500); } catch (InterruptedException e) {}
    }
    
    // 复制构造器
    public ManualCopyPrototype(ManualCopyPrototype source) {
        this.id = source.id + "-copy";
        this.elements = new ArrayList<>(source.elements); // 深拷贝列表
    }
    
    // 工厂方法
    public static ManualCopyPrototype newInstance(ManualCopyPrototype source) {
        ManualCopyPrototype copy = new ManualCopyPrototype(source.id + "-factory");
        copy.elements = new ArrayList<>(source.elements);
        return copy;
    }
    
    public void addElement(String element) { elements.add(element); }
    
    public void printStatus() {
        System.out.println(id + " - Elements: " + elements + 
                         " (Hash: " + System.identityHashCode(elements) + ")");
    }
}


public class PrototypeDemo {
    public static void main(String[] args) throws Exception {
        System.out.println("\n=== 手动复制实现 ===");
        ManualCopyPrototype original3 = new ManualCopyPrototype("Original3");
        original3.addElement("Element1");
        ManualCopyPrototype copy3a = new ManualCopyPrototype(original3);
        ManualCopyPrototype copy3b = ManualCopyPrototype.newInstance(original3);
        copy3a.addElement("Element2");
        copy3b.addElement("Element3");
        original3.printStatus();
        copy3a.printStatus();
        copy3b.printStatus();
    }
}

原型模式实现方式对比及应用场景

实现方式拷贝类型性能复杂度适用场景
Cloneable接口浅拷贝简单对象,无引用或引用不可变
序列化深拷贝复杂对象图,需要完全独立副本
手动复制自定义特殊需求,需要精细控制复制过程

推荐使用场景

  • 简单对象优先使用Cloneable‌:对于没有引用或引用不可变的对象,Cloneable是最简单高效的实现2324
  • 复杂对象使用序列化深拷贝‌:当对象图复杂且需要完全独立副本时,序列化是可靠选择2526
  • 特殊需求考虑手动复制‌:当有特殊复制逻辑或性能要求时,手动复制提供最大灵活性27
  • 注意线程安全问题‌:克隆对象时要注意对象状态的线程安全性13
  • 考虑使用原型管理器‌:对于需要管理多种原型的场景,可以实现原型管理器来集中管理

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头老赵_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值