原型模式

定义

用原型实例指定创建对象的种类,通过拷贝创建新的对象。
不需要知道创建细节,不调用构造方法。
原型模式的核心是clone()方法。

UML类图

在这里插入图片描述
Prototype:原型类,声明一个克隆自己的接口。
ConcretePrototype1、ConcretePrototype2:具体的原型类。

public interface Prototype {
    /**
     * 克隆自身的方法
     * @return
     */
    public Prototype clone();
}

class ConcretePrototype1 implements Prototype{
    @Override
    public Prototype clone() {
        Prototype prototype = new ConcretePrototype1();
        return prototype;
    }
}

class ConcretePrototype2 implements Prototype{
    @Override
    public Prototype clone() {
        Prototype prototype = new ConcretePrototype1();
        return prototype;
    }
}

@AllArgsConstructor
class Client{
    private Prototype prototype;

    public void operation(){
        Prototype newPrototype = prototype.clone();
    }
}

适用场景

类的初始化消耗较多资源。
new一个对象需要非常繁琐的过程(数据准备、访问权限等)
构造函数比较复杂的时候。

特点

原型模式比直接new对象性能高。
当要创建的对象比较复杂的时候,简化了创建对象的过程。
但是必须有clone方法,注意深克隆、浅克隆。实现深克隆的时候可能需要比较复杂的代码。

示例1

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();
    }
}
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 saveOriginMailRecord(Mail mail){
        System.out.println("存储originMail记录,originMail:"+mail.getContent());
    }
}
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.setEmailAddress("姓名");
            mailTemp.setContent("恭喜");
            MailUtil.sendMail(mailTemp);
            System.out.println("克隆的mailTemp:"+mailTemp);
        }
        MailUtil.saveOriginMailRecord(mail);
    }
}

Java里的clone注意

存在浅拷贝和深拷贝。
浅拷贝:对于数据类型是基本类型的成员变量,浅拷贝会值传递给新的对象。
对于数据类型是引用类型的成员变量,浅拷贝会引用传递,clone前后的2个对象的引用类型的成员变量实际上是同一个。
可以通过重写clone方法或者对象序列化的方式实现深拷贝。如下:

public class Pig implements Cloneable,Serializable{
    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 {
        Pig pig = (Pig)super.clone();

        //下面的语句才能深克隆Date属性
        pig.birthday = (Date) pig.birthday.clone();
        return pig;
    }

    public Object deepClone() throws IOException, ClassNotFoundException {
        /**
         * 序列化
         */
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        /**
         * 反序列化
         */
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        Pig pig = (Pig) ois.readObject();
        return pig;
    }

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

public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, ClassNotFoundException {
    Date birthday = new Date(0L);
    System.out.println("如果不修改pig类里的clone方法,pig的birthday是浅克隆,pig1和pig2的birthday一样");
    Pig pig1 = new Pig("佩奇",birthday);
    Pig pig2 = (Pig) pig1.clone();
    System.out.println(pig1 == pig2);   //false
    System.out.println(pig1.getBirthday() == pig2.getBirthday());//false

    Pig pig3 = (Pig) pig1.deepClone();
    System.out.println(pig1 == pig3);//false
    System.out.println(pig1.getBirthday() == pig3.getBirthday());//false
}

示例2

版本1:

@Data
@AllArgsConstructor
@NoArgsConstructor
class Sheep {
    private String name;
    private int age;
    private String color;
}

/**
 * 传统的表示克隆羊群的方法。易理解,号操作。
 * 创建新的羊时,要不停的new,获取原始羊的属性,如果创建的对象比较复杂,效率较低
 */
class Test1{
    public static void main(String[] args) {
        List<Sheep> list = new ArrayList();
        Sheep proto = new Sheep("tom", 1, "白色");
        for (int i = 0; i < 10; i++) {
            list.add(new Sheep(proto.getName(), proto.getAge(),proto.getColor()));
        }
    }
}

版本2:

@Data
@AllArgsConstructor
@NoArgsConstructor
class Sheep implements Cloneable{
    private String name;
    private int age;
    private String color;

    @Override
    protected Object clone()  {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sheep;
    }
}

/**
 * Object里提供了clone()方法,可以将对象复制一份
 */
class Test1{
    public static void main(String[] args) {
        List<Sheep> list = new ArrayList();
        Sheep proto = new Sheep("tom", 1, "白色");
        for (int i = 0; i < 10; i++) {
            list.add((Sheep) proto.clone());
        }
    }
}

示例3

Spring配置bean以原型模式创建:

<bean id="id01" class="com.Student" scope="prototype">
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
	private Integer id;
	private String name;
}
public static void main(String[] args) {
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
	Object bean = applicationContext.getBean("id01");
	Object bean2 = applicationContext.getBean("id01");
	System.out.println("bean2" + bean2);
	System.out.println(bean == bean2); // false
}

Spring源码里关于原型模式的部分是:

class AbstractBeanFactory{
	if(mbd.isSingleton()){
		//略
	}else if(mbd.isPrototype()){
		Object prototypeInstance = null;
		//略
		prototypeInstance = createBean(beanName,mbd,args);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值