10 创建型模式-原型模式

引言:
创建对象的五种方式:

  1. 通过new关键字
  2. 通过Class类的newInstance()方法
  3. 通过Constructor类的newInstance()方法
  4. 利用Clone方法
  5. 反序列化

Clone方法:
其实现方式正是通过调用 Object 类的 clone() 方法来完成。

protected native Object clone() throws CloneNotSupportedException;
public class Person implements Cloneable{
    public String pname;
    public int page;
    public Address address;
    public Person() {}
    
    public Person(String pname,int page){
        this.pname = pname;
        this.page = page;
        this.address = new Address();
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    public void setAddress(String provices,String city ){
        address.setAddress(provices, city);
    }
    public void display(String name){
        System.out.println(name+":"+"pname=" + pname + ", page=" + page +","+ address);
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }
    
}
public class Address {
    private String provices;
    private String city;
    public void setAddress(String provices,String city){
        this.provices = provices;
        this.city = city;
    }
    @Override
    public String toString() {
        return "Address [provices=" + provices + ", city=" + city + "]";
    }
    
}

这是一个我们要进行赋值的原始类 Person。下面我们产生一个 Person 对象,并调用其 clone 方法复制一个新的对象。
注意:调用对象的 clone 方法,必须要让类实现 Cloneable 接口,并且覆写 clone 方法。
测试:

@Test
public void testShallowClone() throws Exception{
    Person p1 = new Person("zhangsan",21);
    p1.setAddress("湖北省", "武汉市");
    Person p2 = (Person) p1.clone();
    System.out.println("p1:"+p1);
    System.out.println("p1.getPname:"+p1.getPname().hashCode());
    
    System.out.println("p2:"+p2);
    System.out.println("p2.getPname:"+p2.getPname().hashCode());
    
    p1.display("p1");
    p2.display("p2");
    p2.setAddress("湖北省", "荆州市");
    System.out.println("将复制之后的对象地址修改:");
    p1.display("p1");
    p2.display("p2");
}

10 创建型模式-原型模式_第1张图片
10 创建型模式-原型模式_第2张图片
10 创建型模式-原型模式_第3张图片
在这里插入图片描述

深拷贝

在这里插入图片描述
10 创建型模式-原型模式_第4张图片

如何实现深拷贝?
  1. 让每个引用类型属性内部都重写clone() 方法
  2. 利用序列化
1 原型模式介绍

定义: 原型模式(Prototype Design Pattern)用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

西游记中的孙悟空 拔毛变小猴,孙悟空这种根据自己的形状复制出多个身外化身的技巧,在面向对象软件设计领域被称为原型模式.孙悟空就是原型对象.
10 创建型模式-原型模式_第5张图片
10 创建型模式-原型模式_第6张图片

2 原型模式原理

10 创建型模式-原型模式_第7张图片
10 创建型模式-原型模式_第8张图片

3 深克隆与浅克隆

在这里插入图片描述
10 创建型模式-原型模式_第9张图片
10 创建型模式-原型模式_第10张图片
10 创建型模式-原型模式_第11张图片
10 创建型模式-原型模式_第12张图片
10 创建型模式-原型模式_第13张图片

3) 浅克隆代码实现:

10 创建型模式-原型模式_第14张图片
测试

@Test
public void test01() throws CloneNotSupportedException {
	ConcretePrototype c1 = new ConcretePrototype();
	ConcretePrototype c2 = c1.clone();
	//输出false
	System.out.println("对象c1和c2是同一个对象?" + (c1==c2));
}
4) 深克隆代码实现
/**
 * 具体原型类
 * 实现Cloneable标识接口,表示当前类对象可复制
 **/
public class ConcretePrototype implements Cloneable, Serializable {

    private Person person;

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public void show(){
        System.out.println("嫌疑人姓名: " + person.getName());
    }

    public ConcretePrototype() {
        System.out.println("具体原型对象创建成功!");
    }

    @Override
    protected ConcretePrototype clone() throws CloneNotSupportedException {
        System.out.println("克隆对象复制成功!");
        return (ConcretePrototype) super.clone();
    }
}
import java.io.Serializable;

public class Person implements Serializable {

    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
//浅拷贝
    @Test
    public void test02() throws CloneNotSupportedException {

        ConcretePrototype c1 = new ConcretePrototype();
        Person p1 = new Person("峰哥");
        c1.setPerson(p1);

        //复制c1
        ConcretePrototype c2 = c1.clone();
        Person p2 = c2.getPerson();
        p2.setName("凡哥");

        c1.show();
        c2.show();
        //输出true,克隆对象和原型对象还是共享name属性的
        System.out.println("对象p1和对象p2是同一个对象吗?" + (p1 == p2));
    }

如果有需求场景中不允许共享同一对象,那么就需要使用深拷贝,如果想要进行深拷贝需要使用到对象序列化流 (对象序列化之后,再进行反序列化获取到的是不同对象).
10 创建型模式-原型模式_第15张图片

4 原型模式应用实例

10 创建型模式-原型模式_第16张图片
10 创建型模式-原型模式_第17张图片

代码实现
广告模板代码
/**
 * 广告模板
 **/
public class AdvTemplate {

    //广告信名称
    private String advSubject = "xx银行本月还款达标,可抽iPhone 13等好礼!";

    //广告信内容
    private String advContext = "达标用户请在2022年3月1日到2022年3月30日参与抽奖......";

    public String getAdvSubject() {
        return advSubject;
    }

    public void setAdvSubject(String advSubject) {
        this.advSubject = advSubject;
    }

    public String getAdvContext() {
        return advContext;
    }

    public void setAdvContext(String advContext) {
        this.advContext = advContext;
    }
}

邮件类代码

/**
 * 邮件类
 **/
public class Mail {

    private String receiver; //收件人

    private String subject; //邮件名称

    private String appellation; //称呼

    private String context;  //邮件内容

    private String tail; //邮件尾部 "xx版权所有"

    public Mail(AdvTemplate advTemplate) {
        this.subject = advTemplate.getAdvSubject();
        this.context = advTemplate.getAdvContext();
    }

    public String getReceiver() {
        return receiver;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getAppellation() {
        return appellation;
    }

    public void setAppellation(String appellation) {
        this.appellation = appellation;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }

    public String getTail() {
        return tail;
    }

    public void setTail(String tail) {
        this.tail = tail;
    }
}

客户类

/**
 * 业务场景
 **/
public class Client {

    //发送邮件的数量
    private static int MAX_COUNT = 6;

    //发送邮件
    public static void sendMail(Mail mail){
        System.out.println("标题: " + mail.getSubject() + "\t 收件人: " + mail.getReceiver()
        + "\t ...发送成功!");
    }

    public static void main(String[] args) {

        int i = 0;

        //定义模板
        Mail mail = new Mail(new AdvTemplate());
        mail.setTail("xxx银行版权所有");
        while(i < MAX_COUNT){
            //每封邮件不同的信息
            mail.setAppellation(" 先生 (女士)");
            Random random = new Random();
            int num = random.nextInt(999999999);
            mail.setReceiver(num + "@"+"mashibing.com");

            //发送邮件
            sendMail(mail);
            i++;
        }
    }

}

10 创建型模式-原型模式_第18张图片
代码重构
Mail类

public class Mail implements Cloneable {

    private String receiver; //收件人

    private String subject; //邮件名称

    private String appellation; //称呼

    private String context;  //邮件内容

    private String tail; //邮件尾部 "xx版权所有"

    public Mail(AdvTemplate advTemplate) {
        this.subject = advTemplate.getAdvSubject();
        this.context = advTemplate.getAdvContext();
    }

    public String getReceiver() {
        return receiver;
    }

    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getAppellation() {
        return appellation;
    }

    public void setAppellation(String appellation) {
        this.appellation = appellation;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }

    public String getTail() {
        return tail;
    }

    public void setTail(String tail) {
        this.tail = tail;
    }

    @Override
    protected Mail clone() {
        Mail mail = null;

        try {
            return  (Mail)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

Client类

public class Client {

    //发送邮件的数量
    private static int MAX_COUNT = 6;

    //发送邮件
    public static void sendMail(Mail mail){
        System.out.println("标题: " + mail.getSubject() + "\t 收件人: " + mail.getReceiver()
                + "\t ...发送成功!");
    }

    public static void main(String[] args) {

        int i = 0;

        //定义模板
        Mail mail = new Mail(new AdvTemplate());
        mail.setTail("xxx银行版权所有");

        while(i < MAX_COUNT){
            //每封邮件不同的信息
            Mail cloneMail = mail.clone();
            cloneMail.setAppellation(" 先生 (女士)");
            Random random = new Random();
            int num = random.nextInt(999999999);
            cloneMail.setReceiver(num + "@"+"mashibing.com");

            //发送邮件
            sendMail(cloneMail);
            i++;
        }
    }
}
5 原型模式总结

原型模式的优点:
10 创建型模式-原型模式_第19张图片
在这里插入图片描述
10 创建型模式-原型模式_第20张图片
原型模式缺点:
需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时需要修改源代码,违背了开闭原则.

使用场景

10 创建型模式-原型模式_第21张图片

你可能感兴趣的:(设计模式,原型模式)