原型模式

定义与类型

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

适用场景

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

优点

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

缺点

  • 必须具备克隆方法
  • 对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
  • 深拷贝、浅拷贝要运用得当

原型的扩展

  • 深克隆
  • 浅克隆
    看下面代码:
package design.prototype;

public class Mail {
    private String name;
    private String emailAddress;
    private String content;

    public Mail() {
        System.out.println("Mail class Constructor");
    }

    public String getName() {
        return name;
    }

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

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }

    public String getContent() {
        return content;
    }

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

    @Override
    public String toString() {
        return "Mail{" +
                "name='" + name + '\'' +
                ", emailAddress='" + emailAddress + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}
package design.prototype;

import java.text.MessageFormat;

public class MailUtil {
    public static void sendMail(Mail mail){
        String outputContent = "向 {0} 同学,邮件地址:{1}," +
                "邮件内容:{2}.发送邮件成功";
        System.out.println(MessageFormat.format(outputContent, mail.getName(),mail.getEmailAddress(), mail.getContent()));
    }

    public static void saveOriginMailRecod(Mail mail){
        System.out.println("存储originMain记录,originMain:"+mail.getContent());
    }
}
package design.prototype;

public class Test {
    public static void main(String[] args) {
        Mail mail = new Mail();
        mail.setContent("初始化模板");
        for(int i=0;i<10;i++){
            mail.setName("姓名"+i);
            mail.setContent("恭喜您,中奖了");
            mail.setEmailAddress("姓名"+i+"@qq.com");
            MailUtil.sendMail(mail);

        }

        MailUtil.saveOriginMailRecod(mail);

    }
}

假设new Mail方法非常复杂,并且在循环中产生大量的对象,那就可以用克隆来实现。

package design.prototype;

public class Mail implements Cloneable{
    private String name;
    private String emailAddress;
    private String content;

    public Mail() {
        System.out.println("Mail class Constructor");
    }

    public String getName() {
        return name;
    }

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

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }

    public String getContent() {
        return content;
    }

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

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

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

import java.text.MessageFormat;

public class MailUtil {
    public static void sendMail(Mail mail){
        String outputContent = "向 {0} 同学,邮件地址:{1}," +
                "邮件内容:{2}.发送邮件成功";
        System.out.println(MessageFormat.format(outputContent, mail.getName(),mail.getEmailAddress(), mail.getContent()));
    }

    public static void saveOriginMailRecod(Mail mail){
        System.out.println("存储originMain记录,originMain:"+mail.getContent());
    }
}
package design.prototype;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Mail mail = new Mail();
        mail.setContent("初始化模板");
        System.out.println("初始化"+"mail:"+mail);
        for(int i=0;i<10;i++){
            Mail mailTemp = (Mail) mail.clone();
            mailTemp.setName("姓名"+i);
            mailTemp.setContent("恭喜您,中奖了");
            mailTemp.setEmailAddress("姓名"+i+"@qq.com");
            MailUtil.sendMail(mailTemp);
            System.out.println("mailTemp"+mailTemp);
        }

        MailUtil.saveOriginMailRecod(mail);

    }
}

再来看一个例子:

package design.prototype.clone;

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

    @Override
    public String toString() {
        return "pig{" +
                "name='" + name + '\'' +
                ", birthday=" + birthday +
                '}'+super.toString();
    }
}
package design.prototype.clone;

import java.util.Date;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date birthday = new Date(0L);
        pig pig = new pig("佩奇",birthday);
        pig pig1 = (design.prototype.clone.pig) pig.clone();

        System.out.println(pig);
        System.out.println(pig1);

        pig.getBirthday().setTime(6666666666L);
        System.out.println(pig);
        System.out.println(pig1);
    }
}

只改了pig的生日,pig1的生日也变了。
在这里插入图片描述
这个birthday引用的是同一个对象,改其中一个另一个也会改变,这个是浅克隆,如果要深克隆的话要怎么做呢?其实很简答,只需要在克隆方法中这样写:
在这里插入图片描述
再运行一下:
在这里插入图片描述
这下就对了。

克隆破坏单例

package design.singleton;

import java.io.Serializable;

public class HungrySingleton implements Serializable,Cloneable{
    private final static HungrySingleton hungrySingleton;

    static {
        hungrySingleton = new HungrySingleton();
    }

    private HungrySingleton(){

        if (hungrySingleton != null){
            throw new RuntimeException("单例构造器禁止使用反射");
        }
    }
    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }

    private Object readResolve(){
        return hungrySingleton;
    }

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

import design.singleton.HungrySingleton;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        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接口,还有就是看下面代码:

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

在重载方法中改成上面的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值