Java 杂谈

设计模式之原型(Prototype)

2018-07-27  本文已影响8人  ikonan

介绍

原型模式是一个创建型的模式。原型二字表明了改模式应该有一个样板实例,用户从这个样板对象中复制一个内部属性一致的对象,这个过程也就是我们称的“克隆”。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。

使用场景

UML类图

原型模式UML类图

原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:

简单示范(浅复制)

定义Book类和Author类:

public class Author {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class Book implements Cloneable{

    private String title;
    private int pageNum;
    private Author author;

    public Book clone() {
        Book book = null;
        try {
            book = (Book)super.clone();
        } catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return book;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }
}

测试

public class PrototypeTest {

    public static void main(String[] args) {

        Book book1 = new Book();
        Author author = new Author();
        author.setName("dsguo");
        author.setAge(29);

        book1.setAuthor(author);
        book1.setTitle("springboot颠覆者开发");
        book1.setPageNum(345);

        Book book2 = book1.clone();

        book2.setTitle("Gof设计模式");
        book2.getAuthor().setName("zhangchao");

        System.out.println(book1==book2);
        System.out.println("book1.pageNum:"+book1.getPageNum());
        System.out.println("book2.pageNum:"+book2.getPageNum());

        System.out.println("book1.title:"+book1.getTitle());
        System.out.println("book2.title:"+book2.getTitle());

        System.out.println("book1.author.name:"+book1.getAuthor().getName());
        System.out.println("book2.author.name:"+book2.getAuthor().getName());
    }

}

运行结果:
false
book1.pageNum:345
book2.pageNum:345
book1.title:springboot颠覆者开发
book2.title:Gof设计模式
book1.author.name:zhangchao
book2.author.name:zhangchao

解释:
细心观察发现,最后两个书本内容输出是一致的。引用类型的新对象book2的author只是单纯指向了this.author引用,并没有重新构造一个author对象,然后将原始书本的author添加到新的author对象中,这样导致book2中的author与原始书本中的是同一个对象。因此,修改其中一个书本的作者,另一个书本也会受到影响。

如何解决?因为Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、集合、容器对象、引用对象等都不会拷贝;所以采用深拷贝。

深拷贝应用

Auhor类也实现Cloneable接口

public class Author implements Cloneable{

    private String name;
    private int age;

    public Author clone() {
        Author author = null;
        try {
            author = (Author)super.clone();
        } catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return author;

    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Book类clone方法新增代码 book.author = this.author.clone();

public class Book implements Cloneable{

    private String title;
    private int pageNum;
    private Author author;

    public Book clone() {
        Book book = null;
        try {
            book = (Book)super.clone();
            book.author = this.author.clone();
        } catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return book;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }
}

运行结果:

false
book1.pageNum:345
book2.pageNum:345
book1.title:springboot颠覆者开发
book2.title:Gof设计模式
book1.author.name:dsguo
book2.author.name:zhangchao

说明:上面的利用Cloneable接口实现拷贝的功能,但是只得注意的是如果拷贝的对象里面存在多个对象或者多级对象,则每个对象都要实现Cloneable接口。逐层的实现要拷贝的内容。下面我们将介绍一种只需要实现Serializable接口然后自定义的一种深度拷贝。

自定义深度复制方法

Java中的深复制一般是通过对象的序列化和反序列化得以实现。序列化时,需要实现Serializable接口。
注意:不仅Book类需要实现Serializable接口,Author同样也需要实现Serializable接口!!

Author类 示例

import java.io.Serializable;

public class Author implements Serializable {

    private String name;
    private int age;


    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Book类示例:

public class Book implements Serializable{

    private String title;
    private int pageNum;
    private Author author;


    public Book deepClone() throws  IOException, ClassNotFoundException{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        // 读出二进制流产生的新对象
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (Book) ois.readObject();
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }
}

输出结果

false
book1.pageNum:345
book2.pageNum:345
book1.title:springboot颠覆者开发
book2.title:Gof设计模式
book1.author.name:dsguo
book2.author.name:zhangchao

总结

优点

缺点

上一篇下一篇

猜你喜欢

热点阅读