Java 设计模式之原型模式

作者: adm 分类: java 发布时间: 2022-08-09

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

原型模式是创建型模式的一种,主要用于创建重复的对象,

主要角色:

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

具体原型类:实现抽象原型的clone()方法。

访问类:使用具体原型类的clone()方法复制出新的对象。

二、实现
原型模式可以分为浅克隆和深克隆:

浅克隆:创建一个新对象,新对象的属性和原对象完全相同,但是非基本数据类型,仍指向原有属性对象的内存地址。

深克隆:创建一个新对象,属性中的对象也会被克隆,不指向原对象的内存地址。

三、浅克隆
举例:

比如我有一个老婆,这个老婆身材完美,前凸后翘,但是一个老婆满足不了我,我想多要一个一模一样的老婆,此时可以通过原型模式复制出新的老婆。

代码实现:

抽象原型类:

java的Object类中提供了clone()方法来实现克隆,Cloneable接口是指上面说到的抽象原型类,所以我们使用Cloneable当作抽象原型类。

具体原型类:

//老婆类 实现Cloneable接口
public class Wife implements Cloneable {
    private int age = 20;
    private int height = 165;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    //重写clone方法
    @Override
    public Wife clone() throws CloneNotSupportedException {
        return (Wife)super.clone();
    }

    @Override
    public String toString() {
        return "Wife{" +
                "age=" + age +
                ", height=" + height +
                '}';
    }
}

使用:

public static void main(String[] args) throws CloneNotSupportedException {
        //创建原型对象
        Wife wife = new Wife();
        //通过原型对象创建新对象
        Wife wife2 = wife.clone();
        //要一个大一些的
        wife2.setHeight(170);
    }

输出:

Wife{age=20, height=165}
Wife{age=20, height=170}

此时通过原型模式(浅拷贝)就创建出了我的第二个身高不同老婆。非常满意。

四:深克隆
举例:

为了验证深浅克隆的区别,我们把Wife中的参数封装成对象试试看。

//老婆属性
public class Param implements Serializable{
    private int age = 20;
    private int height = 165;

    public Param(int age,int height){
        this.age = age;
        this.height = 165;
    }
    
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Param{" +
                "age=" + age +
                ", height=" + height +
                '}';
    }
}

//老婆类
public class Wife implements Cloneable,Serializable {
    //老婆属性
    private Param param;

    public Param getParam() {
        return param;
    }

    public void setParam(Param param) {
        this.param = param;
    }

    @Override
    public Wife clone() throws CloneNotSupportedException {
        return (Wife)super.clone();
    }
}

使用:

public static void main(String[] args) throws CloneNotSupportedException {
        //创建原型对象
        Wife wife = new Wife();
        //设置属性
        wife.setParam(new Param(20,165));

        //通过原型对象创建新对象
        Wife wife2 = wife.clone();
        //修改新对象的身高
        wife2.getParam().setHeight(170);
        System.out.println(wife.getParam().toString());
        System.out.println(wife2.getParam().toString());
    }

输出:

Param{age=20, height=170}
Param{age=20, height=170}

为什么只修改了wife2的身高,wife的身高也变了呢?这怎么行,原因就是因为目前还是浅克隆,写这段代码就是为了验证深浅克隆,可以看出 wife中的params只要修改了一个,就都会发生变化,可见两个param所指向的内存地址还是相同的。解决办法就是深克隆。

深克隆实现:

深克隆可以使用流的方式来实现,只需要在原型类中的clone方法中来实现即可。

@Override
    public Wife clone() throws CloneNotSupportedException {
        //获取clone的对象
        Wife wife = (Wife) super.clone();
        try{
            //把对象写入到字节流中
            ByteArrayOutputStream baos =new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(wife);

            //把字节流转化为对象
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            return (Wife) ois.readObject();
        }catch (IOException | ClassNotFoundException e){
            e.printStackTrace();
        }
        return wife;
    }

使用输出:

Param{age=20, height=165}
Param{age=20, height=170}

此时通过原型模式的深克隆就得到了两个身高不一样的老婆。

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!