努力保头发的打工人
努力保头发的打工人
发布于 2020-12-12 / 23 阅读 / 0 评论 / 0 点赞

原型模式

1概述

1.1简介

原型模式指定创建对象的种类,并且通过拷贝这些原型创建新的对象,就是创建对象是不使用new,而是通过拷贝的方式创建对象。

1.2 原型模式的优点

  • 性能好:原型模式是在内存二进制流中的拷贝,比new性能好很多。

  • 逃避构造函数的约束:既是缺点也是优点,拷贝是构造函数不会执行。

1.3使用场景

  • 资源优化

  • 性能和安全要求的场景

  • 一个对象多个修改者的场景

原型模式很少单独出现,一般和工厂方法模式一起出现,通过clone的方法创建一个新的对象,然后由工厂方法提供给调用者。Java中类实现CloneAble接口来使用。

1.4 注意事项

clone方法是浅拷贝,类的基本类型的成员变量与string类型是拷贝了一份,引用类型的不会重新创建对象,而是将引用指向了原来的变量的内存地址。因此,两个类公用一个引用对象。

如果想要深拷贝可以自行单独修改下clone方法,或者使用二进制流来操作对象,序列化对象再反序列化实现深拷贝。

另外,clone与对象final关键字有冲突的。如果使用clone方法不要在成员变量上使用final关键字。

2 简单实践

原型通用类图如下,比价简单,其实就是实现cloneable接口的一个类

原型通用类图.png

创建一个电影类实现cloneable接口

**
 * @author chiangtaol
 * @date 2020-12-02
 * @describe 电影
 */
@Data
@Builder
public class Movie implements Cloneable{
​
    /**
     * 标题
     */
    private String title;
​
    /**
     * 内容
     */
    private String content;
​
    /**
     * 演员
     */
    private ArrayList<String> actors;
​
​
    @Override
    protected Movie clone(){
        Movie movie = null;
        try {
            movie = (Movie) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("拷贝失败");
        }
        return movie;
    }
}

再测试类中使用

/**
 * @author chiangtaol
 * @date 2020-12-02
 * @describe
 */
class MovieTest {
​
    @Test
    public void test() throws Exception{
        // 创建一个电影
        Movie movie = Movie.builder().title("最后的进化").content("关于成长的...").actors(new ArrayList<>()).build();
        movie.getActors().add("太一");
​
        Movie clone = movie.clone();
        clone.getActors().add("阿和");
​
        System.out.println(movie.toString());
        System.out.println(clone.toString());
    }
}

执行结果如下:

Movie(title=最后的进化, content=关于成长的..., actors=[太一, 阿和]) Movie(title=最后的进化, content=关于成长的..., actors=[太一, 阿和])

虽然拷贝成功了,但是1.4说的浅拷贝的问题出来了,公用了一个私有成员变量,所以可以在movie修改下clone方法,

@Override
protected Movie clone(){
    Movie movie = null;
    try {
        movie = (Movie) super.clone();
        movie.setActors((ArrayList<String>) this.actors.clone());
    } catch (CloneNotSupportedException e) {
        System.out.println("拷贝失败");
    }
    return movie;
}

测试代码执行的结果就改为:

Movie(title=最后的进化, content=关于成长的..., actors=[太一]) Movie(title=最后的进化, content=关于成长的..., actors=[太一, 阿和])

这样深拷贝后两个对象就互相没有关系了。