23种设计模式:07原型模式

错误案例

原型模式在实际项目中,应用也非常常见,比如:过年时候,我想要给3个同学发送一封祝福的信,但祝福的信中,有细小的差距,我希望不重新写信了,拷贝原来的信息,然后修改一下,但是由于java值传递的特殊性,可能我修改第二封后,第一封也会被修改,比如:

  • 这里模拟信封
package design.prototype;
public class Letter {
    public String blessing;
    public String end;
    public String name;

    public Letter(String blessing,String end) {
        this.blessing = blessing;
        this.end = end;
    }

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

    public void send(){
        System.out.println("已经向" + this.name + "发送");
    };

    public void read(){
        System.out.println(this.blessing + this.name + this.end);
    };
}

  • 这里模拟编辑和发送
    public static void main(String[] args) {
        Letter letter01 = new Letter("新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝","新春快了");
        letter01.setName("张三");
        letter01.send();

        Letter letter02 = letter01;
        letter02.setName("赵四");
        letter02.send();

        Letter letter03 = letter02;
        letter03.setName("王五");
        letter03.send();

        letter01.read();
        letter02.read();
        letter03.read();

    }
  • 结果就很尴尬了,他们3个都接收到的是“王五”的称呼
已经向张三发送
已经向赵四发送
已经向王五发送
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝王五新春快了
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝王五新春快了
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝王五新春快了

原型模型

这里我们就的想办法,让拷贝赋值后的数据被修改了,也不会影响之前的数据,于是,我们修改代码如下:

  • 在Letter中增加一个clone()方法
package design.prototype;

public class Letter {
    public String blessing;
    public String end;
    public String name;

    public Letter(String blessing,String end) {
        this.blessing = blessing;
        this.end = end;
    }

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

    public void send(){
        System.out.println("已经向" + this.name + "发送");
    };

    public void read(){
        System.out.println(this.blessing + this.name + this.end);
    };

    //注意 增加的代码在这里
    public Letter clone(){
        Letter letter = new Letter(this.blessing,this.end);
        letter.setName(this.name);
        return letter;
    }
}

  • 然后主程序中,修改为如下:
    public static void main(String[] args) {
        Letter letter01 = new Letter("新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝","新春快了");
        letter01.setName("张三");
        letter01.send();

        Letter letter02 = letter01.clone(); //这里改变了
        letter02.setName("赵四");
        letter02.send();

        Letter letter03 = letter02.clone();//这里改变了
        letter03.setName("王五");
        letter03.send();

        letter01.read();
        letter02.read();
        letter03.read();

    }
  • 输出就正常了
已经向张三发送
已经向赵四发送
已经向王五发送
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝张三新春快了
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝赵四新春快了
新年到,鸿运照,烦恼的事儿往边靠,爱情滋润没烦恼,祝王五新春快了

总结

原型模式是不是很简单,相信很多人没有学过原型模式,也会在实际项目中写出原型模式。

  • clone():在实际业务中,可能Letter类中还有非基本类型,也就是不能直接赋值,需要再次深度克隆的情况,是否需要深度克隆,需要根据你们的具体业务场景来实现
  • Object中也有一个protected类型的clone()方法,我们可以让Letter实现Cloneable接口,然后重写并调用受保护的Object.clone()方法即可
public class Letter implements Cloneable{
    … 省略代码 …
    @Override
    public Object clone() throws CloneNotSupportedException {
//        Letter letter = new Letter(this.blessing,this.end);
//        letter.setName(this.name);
        return super.clone();
    }
}    
  • 调用放入如下
        Letter letter02 = (Letter) letter01.clone();
        System.out.println(letter02 != letter01); //true 必须的,这样才能保证letter02是另外一个类
        System.out.println(letter02.getClass() == letter01.getClass()); // true 相等不是绝对要求
        System.out.println(letter02.equals(letter01)); //false 不是绝对要求

这里不深入了,有兴趣的同学可以打开Object类即可看到他详细的讲解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值