• 10 创建型模式-原型模式


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

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

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

    protected native Object clone() throws CloneNotSupportedException;
    
    • 1
    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;
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    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 + "]";
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这是一个我们要进行赋值的原始类 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");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    深拷贝

    在这里插入图片描述
    在这里插入图片描述

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

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

    西游记中的孙悟空 拔毛变小猴,孙悟空这种根据自己的形状复制出多个身外化身的技巧,在面向对象软件设计领域被称为原型模式.孙悟空就是原型对象.
    在这里插入图片描述
    在这里插入图片描述

    2 原型模式原理

    在这里插入图片描述
    在这里插入图片描述

    3 深克隆与浅克隆

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    3) 浅克隆代码实现:

    在这里插入图片描述
    测试

    @Test
    public void test01() throws CloneNotSupportedException {
    	ConcretePrototype c1 = new ConcretePrototype();
    	ConcretePrototype c2 = c1.clone();
    	//输出false
    	System.out.println("对象c1和c2是同一个对象?" + (c1==c2));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    //浅拷贝
        @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));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    如果有需求场景中不允许共享同一对象,那么就需要使用深拷贝,如果想要进行深拷贝需要使用到对象序列化流 (对象序列化之后,再进行反序列化获取到的是不同对象).
    在这里插入图片描述

    4 原型模式应用实例

    在这里插入图片描述
    在这里插入图片描述

    代码实现
    广告模板代码
    /**
     * 广告模板
     **/
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    邮件类代码

    /**
     * 邮件类
     **/
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    客户类

    /**
     * 业务场景
     **/
    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++;
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在这里插入图片描述
    代码重构
    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;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    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++;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    5 原型模式总结

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

    使用场景

    在这里插入图片描述

  • 相关阅读:
    Ubuntu下VMware出现:Unable to install all modeules.的解决方法
    搭建GraphQL服务
    41-数组 _ 数组作为函数参数
    【远程调用 MySQL数据库并操作】——使用NATAPP搭建内网穿透远程访问MySQL数据库并使用 Python新建、写入、读取、删除数据【详细版】
    Django+vue自动化测试平台(24)-- 接口自动化之处理变量
    npm包【详解】(内含npm包的开发、发布、安装、更新、搜索、卸载、查看、版本号更新规则、package.json详解等)
    基于SpringBoot的在线商城系统设计与实现
    java中发射实现的三种方式
    9.18算法
    java基础知识
  • 原文地址:https://blog.csdn.net/weixin_39563769/article/details/133998011