JAVA设计模式—原型模式笔记

问题:clone 一个 Car 对象 ,clone 多次。

1.传统模式:

直接通过 new 的方式创建多个 Car 对象,创建的时候把原来 Car 对象的属性赋给新的对象。

//实体类
public class Car {
    private String name;
    private String color;
    private int size;

    public Car() {
    }

    public Car(String name, String color, int size) {
        this.name = name;
        this.color = color;
        this.size = size;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", size=" + size +
                '}';
    }
}
//测试类
public class TradTest {
    public static void main(String[] args) {
        Car car = new Car("大众","黑色",18);
        //1.传统模式复制对象
        Car car1 = new Car(car.getName(),car.getColor(),car.getSize());
        Car car2 = new Car(car.getName(),car.getColor(),car.getSize());
        Car car3 = new Car(car.getName(),car.getColor(),car.getSize());
        System.out.println(car1);
        System.out.println(car2);
        System.out.println(car3);
    }
}

传统模式的优缺点:

  1. 优点是很好理解,代码简单
  2. 创建新对象时,总是抓取原对象的属性,如果对象复杂,效率会很低
  3. 总是需要重新初始化对象,而不是动态地获得对象运行时的状态, 不够灵活

2.原型模式

原型模式介绍:

  1. 原型模式(Prototype 模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
  2. 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
  3. 工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即 对象.clone()

2.1 使用原型模式改进传统方式,让程序具有更高的效率和扩展性。

对象实体类需要实现 Cloneable 接口,并且重写 clone() 方法。

//实体类 Car
public class Car implements Cloneable{
    private String name;
    private String color;
    private int size;
    public Country country;

    public Car() {
    }

    public Car(String name, String color, int size) {
        this.name = name;
        this.color = color;
        this.size = size;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", size=" + size +
                ", country=" + country +
                '}';
    }

    @Override
    public Object clone() {
        Car car = null;
        try{
            car = (Car) super.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return car;
    }
}
//实体类 Country ,Car 类的属性包含该对象
public class Country implements Cloneable{
    private String name;

    public Country(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Country{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    public Object clone() {
        Country country = null;
        try {
            country = (Country) super.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return country;
    }
}
//测试类
public class SimpleCopy {
    public static void main(String[] args) {
        //2.浅拷贝复制对象
        Car c1 = new Car("大众","黑色",18);
        c1.country = new Country("德国");
        Car c2 = (Car) c1.clone();
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c1.country.hashCode());
        System.out.println(c2.country.hashCode());
    }
}

2.2 浅拷贝和深拷贝

2.2.1 浅拷贝介绍

1.对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。

2.对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。实际上两个对象的该成员变量都指向同一个实例,在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值

3.上面的案例就是浅拷贝,浅拷贝使用默认的 clone() 方法实现。如果我们修改 c2 的 country 属性的数据,那么 c1 的 country 数据也会随之改变。

2.2.2 深拷贝介绍

1.复制对象的所有基本数据类型的成员变量值

2.为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝

深拷贝方式 1:重写 clone() 方法来实现深拷贝

深拷贝方式 2:通过对象序列化实现深拷贝(推荐)

2.2.3 重写 clone() 方法实现深拷贝

//Car 实体类
public class Car implements Cloneable{
    private String name;
    private String color;
    private int size;
    public Country country;

    public Car() {
    }

    public Car(String name, String color, int size) {
        this.name = name;
        this.color = color;
        this.size = size;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", size=" + size +
                ", country=" + country +
                '}';
    }

    @Override
    public Object clone() {
        Car car = null;
        try{
            car = (Car) super.clone();
            car.country = (Country) car.country.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return car;
    }
}
//Country 实体类
public class Country implements Cloneable{
    private String name;

    public Country(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Country{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    public Object clone() {
        Country country = null;
        try {
            country = (Country) super.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return country;
    }
}
//测试类
public class DeepCopy1 {
    public static void main(String[] args) {
        //1.深拷贝方式一:重写clone()
        Car car = new Car("五菱","红色",18);
        car.country = new Country("中国");
        Car clone = (Car) car.clone();
        System.out.println(car);
        System.out.println(clone);
        System.out.println(car.country.hashCode());
        System.out.println(clone.country.hashCode());
    }
}

2.2.4 通过序列化实现深拷贝

public class Car implements Serializable,Cloneable {
    private static final long serialVersionUID = 54645442L;
    private String name;
    private String color;
    private int size;
    public Country country;

    public Car() {
    }

    public Car(String name, String color, int size) {
        this.name = name;
        this.color = color;
        this.size = size;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", size=" + size +
                ", country=" + country +
                '}';
    }

    //自定义克隆方法
    public Car cloneCar() {
        Car car = null;
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            car = (Car) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ois.close();
                bis.close();
                oos.close();
                bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return car;
    }
}
public class Country implements Serializable, Cloneable{
    private static final long serialVersionUID = 34545442L;
    private String name;

    public Country(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Country{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    public Object clone() {
        Country country = null;
        try {
            country = (Country) super.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return country;
    }
}
public class DeepCopy2 {
    public static void main(String[] args) {
        //2.深拷贝方式二:实现序列化
        Car car = new Car("五菱","红色",18);
        car.country = new Country("中国");
        Car clone = car.cloneCar();
        System.out.println(car);
        System.out.println(clone);
        System.out.println(car.country.hashCode());
        System.out.println(clone.country.hashCode());
    }
}

2.3 原型模式注意事项

  1. 创建新的对象比较复杂时,可以用原型模式简化对象的创建过程,能够提高效率
  2. 不用重新初始化对象,而是动态地获得对象运行时的状态
  3. 原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,不用修改代码
  4. 在实现深拷贝时可能需要比较复杂的代码
  5. 缺点:需要为每一个类配备一个clone() 方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值