设计模式[3]-原型模式

代码:https://gitee.com/Aes_yt/design-pattern

原型模式

概念

原型模式将一个已经创建的实例作为原型,复制出一个和原型相同的新对象。

包括三种角色:

  • 抽象原型:抽象角色,提供具体原型需要实现的接口
  • 具体原型:被复制的对象,实现抽象原型的接口
  • 客户端:发出创建对象的请求。

例子:

先看一个简单的例子,我们设计一个Cloneable接口作为抽象原型,一个Dog类作为具体原型,Dog类关联一个Color类,然后用测试类做客户端来准备复制对象。

image-20211213225141050

Cloneable:

public interface Cloneable<T> {
    T clone();
}

Color:

@Data
public class Color {
    private String name;

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

Dog:

@Data
public class Dog implements Cloneable<Dog> {
    private String name;
    private Color color;

    public Dog() {
        System.out.println("Dog 构造函数。");
    }

    @Override
    public Dog clone() {
        Dog dog = new Dog();
        dog.setColor(this.color);
        dog.setName(this.name);
        return dog;
    }
}

DogTest:

class DogTest {
    @Test
    void show() {
        Dog dog = new Dog();
        dog.setName("小白");
        dog.setColor(new Color("白色"));

        Dog dog2 = dog.clone();
        System.out.println(dog == dog2);
        System.out.println(dog.getColor() == dog2.getColor());

        System.out.println("dog:" + dog.getColor().getName());
        System.out.println("dog2:" + dog2.getColor().getName());

        dog.getColor().setName("黑色");

        System.out.println("dog:" + dog.getColor().getName());
        System.out.println("dog2:" + dog2.getColor().getName());
    }
}

输出:

Dog 构造函数。
Dog 构造函数。
false
true
dog:白色
dog2:白色
dog:黑色
dog2:黑色

分析

首先,我们创建了一个Cloneable接口,然后创建Dog类的实现实现这个接口 ,重写clone()方法,来表示这个类是采用原型模式,这个类可以被复制。

具体的复制方法,在clone()方法中,实例化了Dog类,并赋值给新类。

从DogTest中我们发现了,dog实例对象和复制出来的dog2实例对象是不相等的,说明这是两个类,但是,我们发现了,dog.getColor() 和 dog2.getColor()其实指向的是同一个地址。这就是浅拷贝,只拷贝了数值或者对象的地址,这种情况下,对dog的color做出修改会影响到dog2的color对象的内容。

改进

首先,可以将Color类也实现Cloneable接口,重写clone接口。

@Data
public class Color implements Cloneable<Color>{
    private String name;

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

    @Override
    public Color clone() {
        return new Color(this.name);
    }
}

然后,修改Dog类的clone方法,对Color的对象进行clone。

Dog:

    @Override
    public Dog clone() {
        Dog dog = new Dog();
//        dog.setColor(this.color);
        dog.setColor(this.color.clone());
        dog.setName(this.name);
        return dog;
    }

最后执行测试类,输出:

Dog 构造函数。
Dog 构造函数。
false
false
dog:白色
dog2:白色
dog:黑色
dog2:白色

结果第四行 dog.getColor() == dog2.getColor() 的输出是false,第7行,dog改变颜色变成黑色,没有影响到第8行dog2的白色。拷贝成功。

拓展

java中也有用到原型模式,java.lang.Object 中就有 clone 方法,所以一个对象只需要实现 java.lang.Cloneable接口,然后调用Object类中的clone方法,即可完成对象的拷贝。但是Object类中的clone方法是浅拷贝,而且实现并不是通过像上面的例子一样,通过构造方法直接实例化一个对象出来。

利用自带的Clone方法,实现浅拷贝,代码如下:

@Data
public class Dog implements java.lang.Cloneable {
    private String name;
    private Color color;

    public Dog() {
        System.out.println("Dog 构造函数。");
    }

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

深拷贝利用Color类的clone方法,或者通过对象的序列化实现,就不细说了。

posted @ 2024-08-23 11:05  Aeons  阅读(6)  评论(0编辑  收藏  举报