设计模式之原型模式

本文详细介绍了原型模式,包括定义、适用场景、优点和缺点。在代码演练部分,通过实例展示了如何使用原型模式进行批量邮件发送,并讨论了深克隆与浅克隆的区别。同时,文章还揭示了原型模式可能破坏单例模式的问题及其解决方案,并分析了ArrayList和CacheKey类的源码中克隆的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,定义:

原型实例指定创建对象的种类,通过拷贝这些原型创建新对象
特点:不需要知道任何创建细节,不调用构造函数

二,适用场景

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

三,优点

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

四,缺点

1.必须配备克隆方法
2.对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
3.深拷贝,浅拷贝运用得当

五,代码演练

模拟批量发送邮件
1.Mail代码

public class Mail {
    private String name;
    private String emailAdd;
    private String content;
    public Mail(){
        System.out.println("Mail Class Construct");
    }

    public String getName() {
        return name;
    }

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

    public String getEmailAdd() {
        return emailAdd;
    }

    public void setEmailAdd(String emailAdd) {
        this.emailAdd = emailAdd;
    }

    public String getContent() {
        return content;
    }

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

    @Override
    public String toString() {
        return "Mail{" +
                "name='" + name + '\'' +
                ", emailAdd='" + emailAdd + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

2.MailUtil 代码

public class MailUtil {
    public static void sendMail(Mail mail){
        String outputContext="向{0} 同学,邮件地址:{1},邮箱内容:{2} 发送成功";
        System.out.println(MessageFormat.format(outputContext,mail.getName(),mail.getEmailAdd(),mail.getContent()));
    }
    public static void saveOriginMailRecord(Mail mail){
        System.out.println("存储OriginMail记录,OriginMail:"+mail.getContent());
    }
}

3.Test 类

public class Test {
    public static void main(String[] args) {
        Mail m=new Mail();
        m.setContent("初始化模板");
        for(int i=0;i<10;i++){
            m.setName("姓名:"+i);
            m.setEmailAdd("姓名"+i+"@qq.com");
            m.setContent("你真好看!");
            MailUtil.sendMail(m);
        }
        MailUtil.saveOriginMailRecord(m);
    }
}

结果如图,原始数据丢失
在这里插入图片描述

原型模式改造

Mail类改为

public class Mail implements Cloneable{
    private String name;
    private String emailAdd;
    private String content;
    public Mail(){
        System.out.println("Mail Class Construct");
    }

    public String getName() {
        return name;
    }

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

    public String getEmailAdd() {
        return emailAdd;
    }

    public void setEmailAdd(String emailAdd) {
        this.emailAdd = emailAdd;
    }

    public String getContent() {
        return content;
    }

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

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("clone mail object");
        return super.clone();
    }
}

Test 类改为

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Mail m=new Mail();
        m.setContent("初始化模板");
        System.out.println("初始化mail:"+m);
        for(int i=0;i<10;i++){
            Mail mail= (Mail) m.clone();
            mail.setName("姓名:"+i);
            mail.setEmailAdd("姓名"+i+"@qq.com");
            mail.setContent("你真好看!");
            MailUtil.sendMail(mail);
            System.out.println("克隆mail"+mail);
        }
        MailUtil.saveOriginMailRecord(m);
    }
}

结果如图,原始数据还在
在这里插入图片描述

抽象类实现原型模式

A类

public abstract class A implements Cloneable{
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

B类

public class B extends A {
    public static void main(String[] args) throws CloneNotSupportedException {
        B b=new B();
        b.clone();
    }
}

六,深克隆,浅克隆代码演练

浅克隆代码
1.Pig类

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 {
        return super.clone();
    }

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

2.Test 类

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date birthday=new Date(0L);
        Pig pig1=new Pig("佩奇",birthday);
        Pig pig2= (Pig) pig1.clone();
        System.out.println(pig1);
        System.out.println(pig2);
        pig1.getBirthday().setTime(6666666666666L);
        System.out.println(pig1);
        System.out.println(pig2);
    }
}

在这里插入图片描述
修改 pig1的值时, pig2也会修改
修改为深克隆
重写Pig类中的clone()方法
在这里插入图片描述

七,克隆破坏单例

饿汉式

public class HungrySingleton implements Serializable,Cloneable{
    private final static HungrySingleton hungrySingleton;
    static {
        hungrySingleton=new HungrySingleton();
    }
    private HungrySingleton(){
  if(HungrySingleton.getInstance()!=null){
      throw new RuntimeException("单例构造器禁止反射调用");
  }
    }
    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
    private Object readResolve(){
        return hungrySingleton;
    }

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

测试类

public class Test {
    public static void main(String[] args) throws Exception{
        HungrySingleton hungrySingleton=HungrySingleton.getInstance();
        Method method=hungrySingleton.getClass().getDeclaredMethod("clone");
         method.setAccessible(true);
         HungrySingleton clonehungrySingle= (HungrySingleton) method.invoke(hungrySingleton);
        System.out.println(hungrySingleton);
        System.out.println(clonehungrySingle);
    }
}

在这里插入图片描述

修改方法如下:

重写HungrySingleton的clone()方法
在这里插入图片描述

八,源码解析

1.ArrayList中
在这里插入图片描述
2.CacheKey
在这里插入图片描述
超级多 可以搜实现 Cloneable接口哒~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值