Java设计模式-创建者模式-原型模式

岳庆锦

发布于 2022.03.19 20:39 阅读 822 评论 0

原型模式

 在有些系统中,存在大量相同或者类似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂而且耗时耗资源,用原型模式生成对象就很高效

 定义:用一个已经创建的实例(对象)作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象(除了内存地址和原型不一样,其余都一样)。

 结构 由于Java提供了对象的clone()方法,所以用Java实现原型模式很简单。

 抽象原型类:规定了具体原型对象必须实现的clone()方法。

 具体原型类:实现抽象原型类的clone()方法,它是可被复制的对象。

 访问类:使用具体原型类中的clone()方法来复制新的对象。(克隆出来的是具体原型类的对象)

 实现

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

 原型模式指的是浅克隆。

 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性(比如,引用类型),仍指向原有属性所指向的对象的内存地址。

 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不会再指向原有对象地址。

 Java中的Object类中提供了clone()方法来实现浅克隆。Cloneable接口就是原型模式中的抽象原型类角色,而实现了Cloneable接口的子实现类就是具体原型类

 

在展现代码前,我们要注意以下事项、弄清楚以下问题:

需要注意的是,clone()方法原始访问权限修饰符是protect,但在访问类中要使用clone()方法。如果不提升方法的作用域,访问类就不能使用clone()方法,所以方法的访问修饰符应改为public。

我们要弄清楚的是原型模式克隆对象的方法是不是通过再new一个具体原型类对象来完成的?为了检验这一点,我们在具体实现类的构造方法中打印一句话“原型对象创建完成!”。

如果是通过new具体原型对象来实现克隆,那么我们使用clone()方法时就会打印这句话。即,运行结果中会出现两次“原型对象创建完成!”(第一次是因为创建原型对象,第二次是因为创建克隆的对象)

如果不是通过new具体原型对象来实现克隆,运行结果中就只会出现一次“原型对象创建完成!”。

 

代码展示:

1.Realizetype(具体原型类),实现Cloneable接口,重写父类中的clone()方法。

CloneNotSupportedException异常Object类中的clone()是protected的方法,在没有重写Object的clone()方法且没有实现Cloneable接口的实例上调用clone方法,会报CloneNotSupportedException异常。

public class Realizetype implements Cloneable{

    //看一下构造方法是否被调用
    public Realizetype() {
        System.out.println("具体原型对象创建完成!");
    }

    //1,外面要调用,所以更改为public(原本是protect)
    //2,克隆出来的是具体原型类的对象,所以进行了强制类型转换。
    @Override
    public Object clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return (Realizetype) super.clone();//直接调用父类的clone()方法
    }
}

2.访问类(Client)

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {

        //创建一个原型类对象
        Realizetype realizetype = new Realizetype();//调用无参构造方法
        //调用原型类中的clone方法进行对象的克隆
        Realizetype clone = (Realizetype) realizetype.clone();

        System.out.println("原型对象和克隆出来的是否是同一个对象?"+(realizetype == clone));//false
    }
}

3.运行结果

 结果分析:通过运行结果出现一次“原型对象创建完成!”可以看出,复制的时候没有调用无参构造方法(方法体中的输出语句没有输出),所以super.clone()底层不是通过new对象来实现克隆的。最后的判断原型对象和克隆对象是否指向同一内存地址,结果是false,说明克隆成功。

 下面我们来通过一个具体案例理解体会“原型模式”(浅克隆)

 应用:用原型模式生成“三好学生”奖状。

 分析:同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,可以使用原型模式复制多个“三好学生”奖状出来,然后在修改奖状上的名字即可。

1.抽象原型类(Cloneable接口:java.lang包中的接口)

2.奖状类(Citation),包含成员变量name(学生姓名),对应的set和get方法,重写的父类中的抽象方法clone(),展示奖状的方法show()。

public class Citation implements Cloneable{

    //三好学生的姓名
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    
    //为了效果比较明显
    public void show(){
        System.out.println(name + "同学,在2022年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}

3.访问类(CitationTest)

public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {

        //创建原型对象
        Citation citation = new Citation();
        citation.setName("张三");
        
        //克隆
        Citation citation1 = (Citation) citation.clone();
        citation1.setName("李四");

        //调用show方法展示奖状
        citation.show();
        citation1.show();
    }
}

4.运行结果

 使用场景

 ①对象的创建非常复杂,可以使用原型模式快捷的创建对象。(前提是原型对象必须实现Cloneable接口

 ②性能和安全要求比较高。(不用new对象,而是按照自己的逻辑创建对象