创建型设计模式之原型模式

Posted 丨Jack_Chen丨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建型设计模式之原型模式相关的知识,希望对你有一定的参考价值。

原型模式

概述

优缺点

优点:

1.java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象性能上提升许多

2.使用原型模式将对象复制一份并将其状态保存起来,简化创建对象的过程,以便在需要的时候使用

缺点:

1.需要为每一个类配置一个克隆方法

2克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反开闭原测

3.在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支特深克隆,实现比较麻烦

应用场景

1.类初始化消耗资源较多

2.new产生的一个对象需要非常繁琐的过程(数据准备或访问权限)

3.构造函数处比较复杂

4.循环体中生产大量对象时

5.资源优化场景

6.性能和安全要求的场景

主要角色

1.客户(Client)角色

2.抽象原型(Prototype)角色

3.具体原型(Concrete Prototype)角色

4.原型管理器(Prototype Manager)角色

原型模式的基本使用

创建原型接口

public interface IPrototype<T> 
    T clone();

创建具体需要克隆对象

@Data
@ToString
public class ConcretePrototype implements IPrototype 

    private int age;
    private String name;

    @Override
    public ConcretePrototype clone() 
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setAge(this.age);
        concretePrototype.setName(this.name);
        return concretePrototype;
    

使用

    public static void main(String[] args) 
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(20);
        prototype.setName("jack");
        System.out.println(prototype);

        //拷贝原型对象
        ConcretePrototype cloneType = prototype.clone();
        System.out.println(cloneType);
    

JDK自带原型接口的使用

@Data
@ToString
public class ConcretePrototype implements Cloneable 

    private int age;
    private String name;
    private List<String> hobbies;

    @Override
    public ConcretePrototype clone() 
        try 
            return (ConcretePrototype)super.clone();
         catch (CloneNotSupportedException e) 
            e.printStackTrace();
            return null;
        
    

浅克隆与深度克隆

浅克隆

@Data
@ToString
public class ConcretePrototype implements Cloneable 

    private int age;
    private String name;
    private List<String> hobby;

    @Override
    public ConcretePrototype clone() 
        try 
            return (ConcretePrototype)super.clone();
         catch (CloneNotSupportedException e) 
            e.printStackTrace();
            return null;
        
    

    public static void main(String[] args) 
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(22);
        prototype.setName("jack");
        List<String> hobby = new ArrayList<String>();
        hobby.add("java");
        hobby.add("python");
        hobby.add("go");
        prototype.setHobby(hobby);

        // 拷贝原型对象
        ConcretePrototype cloneType = prototype.clone();
        cloneType.getHobby().add("php");


        System.out.println("原型对象:" + prototype);
        System.out.println("克隆对象:" + cloneType);
        System.out.println(prototype == cloneType);
        System.out.println(prototype.getHobby() == cloneType.getHobby());
    
原型对象:ConcretePrototype(age=22, name=jack, hobby=[java, python, go, php])
克隆对象:ConcretePrototype(age=22, name=jack, hobby=[java, python, go, php])
false
true

深度克隆

可使用序列化方式实现对象的深度克隆

@Data
@ToString
public class ConcretePrototype implements Cloneable, Serializable 

    private int age;
    private String name;
    private List<String> hobby;

    @Override
    public ConcretePrototype clone() 
        try 
            return (ConcretePrototype) super.clone();
         catch (CloneNotSupportedException e) 
            e.printStackTrace();
            return null;
        
    

    public ConcretePrototype deepClone() 
        try 
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);

            return (ConcretePrototype) ois.readObject();
         catch (Exception e) 
            e.printStackTrace();
            return null;
        
    

    public static void main(String[] args) 
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(22);
        prototype.setName("jack");
        List<String> hobby = new ArrayList<String>();
        hobby.add("java");
        hobby.add("python");
        hobby.add("go");
        prototype.setHobby(hobby);

        // 拷贝原型对象
        ConcretePrototype cloneType = prototype.deepClone();
        cloneType.getHobby().add("php");

        System.out.println("原型对象:" + prototype);
        System.out.println("克隆对象:" + cloneType);
        System.out.println(prototype == cloneType);
        System.out.println(prototype.getHobby() == cloneType.getHobby());

    
原型对象:ConcretePrototype(age=22, name=jack, hobby=[java, python, go])
克隆对象:ConcretePrototype(age=22, name=jack, hobby=[java, python, go, php])
false
false

也可这样操作,多克隆一次

    public ConcretePrototype deepClone2() 
        try 
            ConcretePrototype result = (ConcretePrototype) super.clone();
            result.hobby = (List) ((ArrayList) result.hobby).clone();
            return result;
         catch (CloneNotSupportedException e) 
            e.printStackTrace();
            return null;
        
    

单例的破坏

解决方案:禁止深克隆。

1.让单例类不实现Cloneable接口

2.重写clone方法,在clone方法中返回单例对象即可
@Data
@ToString
public class ConcretePrototype implements Cloneable 

    private static  ConcretePrototype instance = new ConcretePrototype();

    private ConcretePrototype()

    public static ConcretePrototype getInstance()
        return instance;
    

    @Override
    public ConcretePrototype clone() 
       return instance;
    

以上是关于创建型设计模式之原型模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之原型模式

原型模式

[设计模式C++go]创建型模式:原型模式

[设计模式C++go]创建型模式:原型模式

[设计模式C++go]创建型模式:原型模式

5.原型模式