创建型-原型模式

2018-10-09  本文已影响0人  iarchitect

原型模式:使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

类型:创建型模式。

角色:
抽象原型类:它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是接口,抽象类,甚至是具体实现类。
具体原型类:实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
客户类:让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化创建一个原型对象,在通过调用该对象的克隆方法即可得到多个相同的对象。

预备知识:
在Java中的数据类型分为基本数据类型(byte,short,int,long,float,double,char,boolean)和引用数据类型(类,接口类型,数组类型,枚举类型,注解类型) ,两者的区别是,基本数据类型在被创建时,在栈上给其划分出一块内存,将数值直接存储在栈上。引用数据类型在被创建时,首先要在栈上给其引用(句柄)分配一块内存,而对象的具体信息都存储在堆内存上,然后由栈上的引用指向堆中对象的地址。

下面以复制一本书为例:
浅拷贝原型模式代码示例:

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;

    @Override
    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 Test {

    public static void main(String[] args) {
        Book book1 = new Book();
        Author author = new Author();
        author.setAge(30);
        author.setName("smart");
        book1.setAuthor(author);
        book1.setTitle("times");
        book1.setPageNum(300);

        Book book2 = book1.clone();

        System.out.println(book1 == book2);
        System.out.println(book1.getAuthor() == book2.getAuthor());
        System.out.println(book1.getTitle() == book2.getTitle());
        System.out.println(book1.getPageNum() == book2.getPageNum());
    }

}

运行结果:


image.png

分析:
根据输出结果我们可以发现,复制出来的对象,在堆上重新开辟了内存空间,对象中各属性保持相等,对于基本数据类型,很好理解,在栈上重新开辟空间,复制相应的zhi,但是对于引用数据类型,说明它们指向的对象是相同的,并没有重新开辟内存空间,即引用类型的属性所指向的对象,并没有复制。我们称其为浅复制或浅拷贝

深拷贝原型模式代码示例:

import java.io.Serializable;

public class AuthorS 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;
    }
}

import java.io.*;

public class BookS implements Serializable {
    private String title;
    private int pageNum;
    private AuthorS authorS;

    public BookS deepClone() throws IOException, ClassNotFoundException {
        //写入当前对象的二进制流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(this);

        //读出二进制流产生的新对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);

        return (BookS) objectInputStream.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 AuthorS getAuthorS() {
        return authorS;
    }

    public void setAuthorS(AuthorS authorS) {
        this.authorS = authorS;
    }
}

public class TestS {

    public static void main(String[] args) throws  Exception{
        BookS bookS1 = new BookS();
        AuthorS authorS = new AuthorS();
        authorS.setAge(30);
        authorS.setName("smart");
        bookS1.setAuthorS(authorS);
        bookS1.setTitle("times");
        bookS1.setPageNum(300);

        BookS bookS2 = bookS1.deepClone();

        System.out.println(bookS1 == bookS2);
        System.out.println(bookS1.getAuthorS() == bookS2.getAuthorS());
        System.out.println(bookS1.getTitle() == bookS2.getTitle());
        System.out.println(bookS1.getPageNum() == bookS2.getPageNum());
    }

}

运行结果:


image.png

分析:
深拷贝不仅在堆上开辟了空间以存储复制出来的对象,甚至连对象中的引用类型的属性所指向的对象也得以复制,重新开辟了堆空间存储。

总结:
优点:
1,当创建的新的对象实例比较复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率。
2,提供了简化的创建结构
3,使用深拷贝的方式保存对象的状态,可辅助实现撤销操作。
缺点:
1,需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了“开闭原则”
2,在实现深拷贝时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深拷贝,每一层对象对应的类都必须支持深拷贝,实现起来可能会比较麻烦。

上一篇 下一篇

猜你喜欢

热点阅读