一、创建型模式

在面向对象的世界里,如何优雅地创建对象,是每一位开发者都会反复思考的问题。直接 new 一个对象固然简单,但当业务复杂度上升、依赖关系变得盘根错节时,这种方式就会让代码变得僵硬、难以维护。

创建型设计模式正是为了解决这一痛点而诞生的一套思想体系。它们将对象的创建与使用分离,通过封装、抽象和延迟实例化等手段,让代码更具灵活性、可扩展性和可测试性。

在 Java 开发中,创建型模式主要包含以下 5 种经典实现:

  1. 单例模式 (Singleton):确保一个类在整个应用中仅有一个实例,并提供一个全局访问点。Java 设计模式・单例模式篇:从思想到代码实现-CSDN博客
  2. 工厂方法模式 (Factory Method):定义一个创建对象的接口,让子类决定实例化哪一个类,将实例化逻辑延迟到子类。Java 设计模式・工厂模式篇:从思想到代码实现-CSDN博客
  3. 抽象工厂模式 (Abstract Factory):提供一个创建一系列相关或依赖对象的接口,而无需指定它们具体的类。Java 设计模式・工厂模式篇:从思想到代码实现-CSDN博客
  4. 建造者模式 (Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Java 设计模式・建造者模式篇:从思想到代码实现-CSDN博客
  5. 原型模式 (Prototype):用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。 

二、原型模式

2.1 介绍

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

2.2 角色

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。

  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。

三、克隆对比

特性 赋值(=) 浅克隆 深克隆
是否创建新对象 否(共享同一个对象) 是(仅外层对象新) 是(所有层级对象都新)
基本类型属性 共享(修改同步) 复制值(修改不同步) 复制值(修改不同步)
引用类型属性 共享引用(修改同步) 共享引用(修改同步) 复制新对象(修改不同步)
== 判断外层对象 true(同一地址) false(新地址) false(新地址)
== 判断引用属性 true(同一地址) true(同一地址) false(新地址)

对象的内存地址(堆内存中的物理地址)是在第一次通过 new/ 反射 / 克隆等方式创建时就永久确定的,后续永远无法修改

四、赋值

4.1 代码

本文以中文为类名,方便理解

public class 用户 {
    private String name;
    private 地址 address;

    public 用户() {
    }

    public 用户(String name, 地址 address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public 地址 getAddress() {
        return address;
    }

    public void setAddress(地址 address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "用户名:" + name + ",地址:" + address.getCity();
    }
}
public class 地址 {
    private String city;

    public 地址() {
    }

    public 地址(String city) {
        this.city = city;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}

4.2 测试

public class 测试 {
    public static void main(String[] args) {
        地址 address = new 地址("上海");
        用户 user1 = new 用户("张三" , address);
        用户 user2 = user1;
        check(user1 , user2);
        user1.setName("李四");
        check(user1 , user2);
        address.setCity("北京");
        check(user1 , user2);
    }

    public static void check(用户 user1 , 用户 user2) {
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user1 == user2);
        System.out.println(user1.getAddress() == user2.getAddress());
    }
}

      

五、浅克隆

5.1 代码实现

Java中的Object类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类

如果没有实现该接口直接调用该方法会报错,因为此方法被定义为 protected native Object clone() throws CloneNotSupportedException

protected 方法的访问规则是:

  • 只能在同一个包内的类,或者子类中被访问。
  • 如果你在一个不相关的类中直接调用 obj.clone(),就会触发这个编译

所以要重写此方法,并把访问范围改成public

public class 用户 implements Cloneable{
    private String name;
    private 地址 address;

    public 用户() {
    }

    public 用户(String name, 地址 address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public 地址 getAddress() {
        return address;
    }

    public void setAddress(地址 address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "用户名:" + name + ",地址:" + address.getCity();
    }

    @Override
    public 用户 clone() {
        try {
            return (用户) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

5.2 测试

public class 测试 {
    public static void main(String[] args) {
        地址 address = new 地址("上海");
        用户 user1 = new 用户("张三" , address);
        用户 user2 = user1.clone();
        check(user1 , user2);
        user1.setName("李四");
        check(user1 , user2);
        address.setCity("北京");
        check(user1 , user2);
    }

    public static void check(用户 user1 , 用户 user2) {
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user1 == user2);
        System.out.println(user1.getAddress() == user2.getAddress());
    }
}

    

六、深克隆

6.1 手动递归重写 clone () 方法

public class 用户 implements Cloneable{
    private String name;
    private 地址 address;

    public 用户() {
    }

    public 用户(String name, 地址 address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public 地址 getAddress() {
        return address;
    }

    public void setAddress(地址 address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "用户名:" + name + ",地址:" + address.getCity();
    }

    @Override
    public 用户 clone() {
        try {
            用户 user = (用户) super.clone();
            user.address = address.clone();
            return user;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
public class 地址 implements Cloneable{
    private String city;

    public 地址() {
    }

    public 地址(String city) {
        this.city = city;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public 地址 clone() {
        try {
            return (地址) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

测试代码不变

  

6.2 给所有类加上Serializable

这种不需要一个一个去重写方法了,只需要把涉及的类都标记可序列化,只需要在需要克隆的方法上添加深克隆的方法

public class 用户 implements Serializable {
    private String name;
    private 地址 address;

    public 用户() {
    }

    public 用户(String name, 地址 address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public 地址 getAddress() {
        return address;
    }

    public void setAddress(地址 address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "用户名:" + name + ",地址:" + address.getCity();
    }

    public 用户 deepClone() throws IOException, ClassNotFoundException {
        // 1. 将对象写入字节流
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        // 2. 从字节流读取新对象
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (用户) ois.readObject();
    }

}
public class 地址 implements Serializable {
    private String city;

    public 地址() {
    }

    public 地址(String city) {
        this.city = city;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}

测试

public class 测试 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        地址 address = new 地址("上海");
        用户 user1 = new 用户("张三" , address);
        用户 user2 = user1.deepClone();
        check(user1 , user2);
        user1.setName("李四");
        check(user1 , user2);
        address.setCity("北京");
        check(user1 , user2);
    }

    public static void check(用户 user1 , 用户 user2) {
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user1 == user2);
        System.out.println(user1.getAddress() == user2.getAddress());
    }
}

  

七、其他相关设计模式

Java 设计模式・总结目录篇:从思想到代码实现-CSDN博客

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐