一天一种JAVA设计模式之五:原型模式

写在前面的话

复习、总结23种设计模式

上一篇

# 一天一种JAVA设计模式之四:建造者模式

原型模式

定义

不通过new关键字来产生一个对象,而是通过对象复制来实现的模式就叫做原型模式

原型模式有两种表现形式:

(1)简单形式、

(2)登记形式

这两种表现形式仅仅是原型模式的不同实现。

1、简单形式的原型模式

这种形式涉及到三个角色:

客户(Client)角色:客户类提出创建对象的请求。

抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。

具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

java 复制代码
package com.design.pattern.prototype.test04;  
  
// 抽象原型角色  
public interface Prototype {  
    /**  
    * 克隆自身的方法  
    *  
    * @return 一个从自身克隆出来的对象  
    */  
    public Object clone();  
    }  

    // 具体原型角色  
    class ConcretePrototype1 implements Prototype {  
        public Prototype clone() {  
            //最简单的克隆,新建一个自身对象,由于没有属性就不再复制值了  
            Prototype prototype = new ConcretePrototype1();  
            return prototype;  
        }  
    }  

    class ConcretePrototype2 implements Prototype {  
        public Prototype clone() {  
            //最简单的克隆,新建一个自身对象,由于没有属性就不再复制值了  
            Prototype prototype = new ConcretePrototype2();  
            return prototype;  
        }  
    }
java 复制代码
package com.design.pattern.prototype.test04;  
  
// 客户端角色  
public class Client {  
    /**  
    * 持有需要使用的原型接口对象  
    */  
    private Prototype prototype;  

    /**  
    * 构造方法,传入需要使用的原型接口对象  
    */  
    public Client(Prototype prototype) {  
        this.prototype = prototype;  
    }  

    public void operation(Prototype example) {  
        //需要创建原型接口的对象  
        Prototype copyPrototype = (Prototype) prototype.clone();  
        System.out.println(copyPrototype);  
    }  
}

2、登记形式的原型模式

作为原型模式的第二种形式,它多了一个原型管理器(PrototypeManager)角色,

该角色的作用是:创建具体原型类的对象,并记录每一个被创建的对象。

3.两种形式的比较

简单形式和登记形式的原型模式各有其长处和短处。

如果需要创建的原型对象数目较少而且比较固定的话,可以采取第一种形式。在这种情况下,原型对象的引用可以由客户端自己保存。

如果要创建的原型对象数目不固定的话,可以采取第二种形式。在这种情况下,客户端不保存对原型对象的引用,这个任务被交给管理员对象。在复制一个原型对象之前,客户端可以查看管理员对象是否已经有一个满足要求的原型对象。如果有,可以直接从管理员类取得这个对象引用;如果没有,客户端就需要自行复制此原型对象。

构造函数不会被执行

java 复制代码
package com.design.pattern.prototype.test01;  
  
    /*  
    如果Things没有实现java.lang.Cloneable接口,  
    在调用super.clone()时会抛出CloneNotSupportedException  
    */  
    public class Things implements Cloneable {  

    public Things() {  
        System.out.println("构造函数被执行...");  
    }  

    @Override  
    protected Object clone() throws CloneNotSupportedException {  
        // 如果Things没有实现java.lang.Cloneable接口,在调用super.clone()时会抛出CloneNotSupportedException  
        return super.clone();  
    }  
  
}

Object类的clone()的原理是从内存中以二进制流的方式进行拷贝,重新分配一个内存块,那构造函数没有被执行也是非常正常的了

java 复制代码
package com.design.pattern.prototype.test01;  
  
/**  
Object类的clone()的原理是从内存中以二进制流的方式进行拷贝,  
重新分配一个内存块,那构造函数没有被执行也是非常正常的了  
*/  
public class Test01构造函数不会被执行 {  

    public static void main(String[] args) {  
        Things things = new Things();  
        try {  
            Object clone = things.clone();  
            System.out.println(things);  
            System.out.println(clone);  
            System.out.println(clone instanceof Things);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

原型模式实现

原型模式的克隆分为浅克隆和深克隆

浅拷贝

Object类的clone()只是拷贝本对象,其内部对象的数组,引用对象都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝

java 复制代码
package com.design.pattern.prototype.test02;  

import java.util.ArrayList;  
import java.util.List;  
  
public class Person implements Cloneable{  

    private List<String> value = new ArrayList<String>();  

    @Override  
    protected Person clone() {  
        try {  
            return (Person) super.clone();  
        } catch (CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return null;  
    }  

    public void addValue(String v) {  
        this.value.add(v);  
    }  

    public List<String> getValue() {  
        return this.value;  
    }  
  
}
java 复制代码
package com.design.pattern.prototype.test02;  
  
import java.util.Arrays;  
  
/*  
Object类的clone()只是拷贝本对象,其内部对象的数组,  
引用对象都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝  
*/  
public class Test02浅拷贝 {  

    public static void main(String[] args) {  
        Person person = new Person();  
        person.addValue("123");  

        Person newPerson = person.clone();  
        newPerson.addValue("456");  

        System.out.println(person);  
        System.out.println(newPerson);  

        // [123, 456]  
        System.out.println(Arrays.toString(person.getValue().toArray(new String[0])));  
        // [123, 456]  
        System.out.println(Arrays.toString(newPerson.getValue().toArray(new String[0])));  
   }  
  
}

深拷贝

深度克隆要深入到多少层,是一个不易确定的问题。在决定以深度克隆的方式复制一个对象的时候,必须决定对间接复制的对象时采取浅度克隆还是继续采用深度克隆。因此,在采取深度克隆时,需要决定多深才算深。此外,在深度克隆的过程中,很可能会出现循环引用的问题,必须小心处理。

java 复制代码
package com.design.pattern.prototype.test03;  
  
import java.util.ArrayList;  
import java.util.List;  
  
public class Person implements Cloneable{  

    private ArrayList<String> value = new ArrayList<String>();  

    @Override  
    protected Person clone() {  
        try {  
            Person clone = (Person) super.clone();  
            clone.value = (ArrayList<String>) this.value.clone();  
            return clone;  
        } catch (CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return null;  
    }  

    public void addValue(String v) {  
        this.value.add(v);  
    }  

    public List<String> getValue() {  
        return this.value;  
    }  
  
}
java 复制代码
package com.design.pattern.prototype.test03;  
  
import java.util.Arrays;  
  
public class Test03深拷贝 {  
  
    public static void main(String[] args) {  
        Person person = new Person();  
        person.addValue("123");  

        Person newPerson = person.clone();  
        newPerson.addValue("456");  

        System.out.println(person);  
        System.out.println(newPerson);  

        // [123]  
        System.out.println(Arrays.toString(person.getValue().toArray(new String[0])));  
        // [123, 456]  
        System.out.println(Arrays.toString(newPerson.getValue().toArray(new String[0])));  
    }  
}

浅拷贝与深拷贝的区别

深拷贝:在对类中引用数据类型(类的实例对象)进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量

浅拷贝:只对类中基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象

浅拷贝和深拷贝是相对的,如果一个对象内部只有基本数据类型,那用 clone() 方法获取到的就是这个对象的深拷贝,而如果其内部还有引用数据类型,那用 clone() 方法就是一次浅拷贝的操作

下一篇

# 一天一种JAVA设计模式之四:建造者模式

相关推荐
ajsbxi1 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
颜淡慕潇1 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
wrx繁星点点1 小时前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
尘浮生2 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea
尚学教辅学习资料2 小时前
基于SpringBoot的医药管理系统+LW示例参考
java·spring boot·后端·java毕业设计·医药管理
金池尽干3 小时前
设计模式之——观察者模式
观察者模式·设计模式
也无晴也无风雨3 小时前
代码中的设计模式-策略模式
设计模式·bash·策略模式
monkey_meng3 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马3 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng3 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust