23种设计模式(三)原型模式

原型模式


原型模式的适用场景:

1.类初始化消耗资源较多
2.new一个对象需要非常繁琐的过程(数据准备,访问权限等)
3.构造函数比较复杂
4.循环产生大量对象时

优点:

1.原型模式比new一个对象性能要高
2.简化创建过程

缺点:

1.必须配备克隆方法(必须重写object的克隆方法)
2.对克隆对象,进行复杂改造的时候,容易引入风险

重要的是克隆
常用的场景:积分抽奖,邮箱,短信
浅克隆:

Cloneable接口 重写clone方法

public class Email implements Cloneable{
    private String name;
    private String address;
    private String content;

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

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

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Email{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", content='" + content + '\'' +
                '}'+super.toString();
    }
}

发送邮件,保存邮件内容

public class EmailUtils {
    public static void sendEmail(Email email){
        String sendfriend="向{0}发送,邮件地址:{1},邮件内容:{2}";
        System.out.println(MessageFormat.format(sendfriend, email.getName(),email.getAddress(),email.getContent()));
    }
    public static void saveOriginMailRecord(Email email){
        System.out.println("存储原始email:"+email.getContent());
    }
}

Email clone=(Email)email.clone(); 克隆

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Email email=new Email();
        email.setContent("测试模板");
        System.out.println(email);
        for (int i = 0; i < 10; i++) {
            Email clone=(Email)email.clone();
            clone.setName("姓名"+i);
            clone.setAddress("qq号"+i+"@qq.com");
            clone.setContent("恭喜您中奖qq币");
            EmailUtils.sendEmail(clone);
            System.out.println("CLONE"+clone);
        }
        EmailUtils.saveOriginMailRecord(email);
    }
}

输出结果

Email{name='null', address='null', content='测试模板'}com.qjc.pattern.creational.prototype.Email@4554617c
向姓名0发送,邮件地址:qq号0@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名0', address='qq号0@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@74a14482
向姓名1发送,邮件地址:qq号1@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名1', address='qq号1@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@1540e19d
向姓名2发送,邮件地址:qq号2@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名2', address='qq号2@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@677327b6
向姓名3发送,邮件地址:qq号3@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名3', address='qq号3@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@14ae5a5
向姓名4发送,邮件地址:qq号4@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名4', address='qq号4@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@7f31245a
向姓名5发送,邮件地址:qq号5@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名5', address='qq号5@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@6d6f6e28
向姓名6发送,邮件地址:qq号6@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名6', address='qq号6@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@135fbaa4
向姓名7发送,邮件地址:qq号7@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名7', address='qq号7@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@45ee12a7
向姓名8发送,邮件地址:qq号8@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名8', address='qq号8@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@330bedb4
向姓名9发送,邮件地址:qq号9@qq.com,邮件内容:恭喜您中奖qq币
CLONEEmail{name='姓名9', address='qq号9@qq.com', content='恭喜您中奖qq币'}com.qjc.pattern.creational.prototype.Email@2503dbd3
存储原始email:测试模板

由此看出new对象一次,然后使用clone方法频繁复制对象

深克隆:
深克隆,就是对象里面包含了一个date对象如果在引用时

public class Pig  implements Cloneable{
    private String name;
    private Date birthday;

    public Pig(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

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

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //深克隆  很容易引起bug
        return super.clone();
    }

    @Override
    public String toString() {
        return "Pig{" +
                "name='" + name + '\'' +
                ", birthday=" + birthday +
                '}'+super.toString();
    }
}
   //深克隆   浅克隆
        Date date=new Date(0L);
        Pig pig=new Pig("佩奇",date);
        Pig pig1= (Pig) pig.clone();
        System.out.println(pig);//date  引用的同一个对象
        System.out.println(pig1);//date
       
        pig.getBirthday().setTime(8888888888L);
        //相同对象
        System.out.println(pig);
        System.out.println(pig1);

输出结果:

Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.qjc.pattern.creational.prototype.clone.Pig@14ae5a5
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.qjc.pattern.creational.prototype.clone.Pig@7f31245a
Pig{name='佩奇', birthday=Tue Apr 14 05:08:08 CST 1970}com.qjc.pattern.creational.prototype.clone.Pig@14ae5a5
Pig{name='佩奇', birthday=Tue Apr 14 05:08:08 CST 1970}com.qjc.pattern.creational.prototype.clone.Pig@7f31245a

由此看出如果我修改了date,导致克隆对象也会被修改,这就是深克隆的问题
在这里插入图片描述
在这里插入图片描述
如何解决此问题,重写clone方法

 @Override
    protected Object clone() throws CloneNotSupportedException {
        Pig pig=(Pig)super.clone();
        pig.birthday= (Date) pig.birthday.clone();
        return pig;
    }
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.qjc.pattern.creational.prototype.clone.Pig@14ae5a5
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.qjc.pattern.creational.prototype.clone.Pig@7f31245a
Pig{name='佩奇', birthday=Tue Apr 14 05:08:08 CST 1970}com.qjc.pattern.creational.prototype.clone.Pig@14ae5a5
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.qjc.pattern.creational.prototype.clone.Pig@7f31245a

这样的话date对象就不存在深克隆这个问题了
jdk中有:
HashMap,ArrayList 等实现了Cloneable接口有兴趣的参考一下

克隆破坏单例模式:懒汉式 这样的话就会出现两个对象

  HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        Method method = hungrySingleton.getClass().getDeclaredMethod("clone");
        method.setAccessible(true);
        HungrySingleton cloneHungrySingleton = (HungrySingleton) method.invoke(hungrySingleton);
        System.out.println(hungrySingleton);
        System.out.println(cloneHungrySingleton);

如何防止这种方式,不实现Cloneable接口,或者让Cloneable,调用另一个方法getInstatance,即可解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值