原创

设计模式之原型模式

温馨提示:
本文最后更新于 2023年11月16日,已超过 433 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

原型模式

原型模式属于创建型设计模式。当直接创建对象的代价较大时,通过复制现有的实例来创建新的实例,不需要知道相应类的信息。例如:数据库查询、IO操作生成等等。

优缺点

优点

  • 提高了对象的创建效率,节省时间和资源;
  • 避免重复对象创建初始化的复杂性;
  • 可以在运行时动态添加和删除对象;
  • 可以保护原始对象,防止意外修改影响原对象;

缺点

  • 不是所有对象一定都可以进行有效的复制;
  • 必须实现Cloneable接口,并重写clone方法。

代码实现

浅拷贝

public class Car implements Cloneable{
    private String brand;
    private Tire tire;
    private String color;
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public Tire getTire() {
        return tire;
    }
    public void setTire(Tire tire) {
        this.tire = tire;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", tire=" + tire +
                ", color='" + color + '\'' +
                '}';
    }
    @Override
    public Car clone() {
        try {
            return (Car) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
public class Tire implements Cloneable{
    private String brand;
    private String color;
    @Override
    public String toString() {
        return "Tire{" +
                "brand='" + brand + '\'' +
                ", color='" + color + '\'' +
                '}';
    }
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public Tire clone() {
        try {
            return (Tire) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
public static void main(String[] args) {
        Tire tire = new Tire();
        tire.setBrand("米其林");
        tire.setColor("黑色");
        Car bmw1 = new Car();
        bmw1.setBrand("宝马");
        bmw1.setColor("黑色");
        bmw1.setTire(tire);
        System.out.println(bmw1);

        Car bmw2 = bmw1.clone();
        tire.setBrand("马牌");
        System.out.println(bmw1);
        System.out.println(bmw2);
    }

运行结果

  • 通过上面的图我们发现,当我们想给第一辆车换个轮胎的时候,第二辆车的轮胎同样被改变,这并不是我们想要的效果。而这里使用的是原型模式的浅拷贝模式。
  • 那我们如何仅给第一辆车换新轮胎而不影响其他车辆呢?这时我们就可以使用深拷贝来实现。

深拷贝

方式一

public class Car implements Cloneable{
    private String brand;
    private Tire tire;
    private String color;
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public Tire getTire() {
        return tire;
    }
    public void setTire(Tire tire) {
        this.tire = tire;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", tire=" + tire +
                ", color='" + color + '\'' +
                '}';
    }
    @Override
    public Car clone() {
        try {
            Car car = (Car) super.clone();
            car.setTire(car.getTire().clone());
            return car;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

方式二

通过序列化对象实现深拷贝。

public class Car implements Cloneable, Serializable {
    private static final long serialVersionUID = -3682987459412388794L;
    private String brand;
    private Tire tire;
    private String color;
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public Tire getTire() {
        return tire;
    }
    public void setTire(Tire tire) {
        this.tire = tire;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", tire=" + tire +
                ", color='" + color + '\'' +
                '}';
    }
    @Override
    public Car clone() {
        try {
            Car car = (Car) super.clone();
            car.setTire(car.getTire().clone());
            return car;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
    public Car deepClone() {
        ByteArrayOutputStream bas = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            bas = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bas);
            oos.writeObject(this);
            bis = new ByteArrayInputStream(bas.toByteArray());
            ois = new ObjectInputStream(bis);
            return (Car) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (Objects.nonNull(bas)){
                    bas.close();
                }
                if (Objects.nonNull(oos)){
                    oos.close();
                }
                if (Objects.nonNull(bis)){
                    bis.close();
                }
                if (Objects.nonNull(ois)){
                    ois.close();
                }
            }catch (IOException e){
                throw new RuntimeException(e);
            }
        }
    }
}

运行结果

深/浅拷贝

原型模式种拷贝对象可分为深拷贝和浅拷贝。

浅拷贝

  • 当拷贝对象只包含基础数据类型时,直接将这些字段复制到新的对象中。
  • 当拷贝对象包含引用数据类型时,克隆对象引用数据类型的地址。

深拷贝

  • 不仅会复制基本数据类型的变量,还会给引用数据类型申请存储空间给对应变量赋值;
正文到此结束
本文目录