设计模式总结篇系列:原型模式(Prototype)
2014-05-23 01:18
302 查看
首先对原型模式进行一个简单概念说明:通过一个已经存在的对象,复制出更多的具有与此对象具有相同类型的新的对象。
在理解Java原型模式之前,首先需要理解Java中的一个概念:复制/克隆。
在博文《Java总结篇系列:java.lang.Object》一文中,对Java中的clone()方法进行了一定的阐述。同时,我们需要知道,Java中的对象复制/克隆分为浅复制和深复制。
一、浅复制:
我们知道,一个类的定义中包括属性和方法。属性用于表示对象的状态,方法用于表示对象所具有的行为。其中,属性既可以是Java中基本数据类型,也可以是引用类型。Java中的浅复制通常使用clone()方式完成。
当进浅复制时,clone函数返回的是一个引用,指向的是新的clone出来的对象,此对象与原对象分别占用不同的堆空间。同时,复制出来的对象具有与原对象一致的状态。
此处对象一致的状态是指:复制出的对象与原对象中的属性值完全相等==。
下面以复制一本书为例:
1.定义Book类和Author类:
2.测试:
由输出的结果可以验证说到的结论。由此我们发现:虽然复制出来的对象重新在堆上开辟了内存空间,但是,对象中各属性确保持相等。对于基本数据类型很好理解,但对于引用数据类型来说,则意味着此引用类型的属性所指向的对象本身是相同的, 并没有重新开辟内存空间存储。换句话说,引用类型的属性所指向的对象并没有复制。
由此,我们将其称之为浅复制。当复制后的对象的引用类型的属性所指向的对象也重新得以复制,此时,称之为深复制。
二、深复制:
Java中的深复制一般是通过对象的序列化和反序列化得以实现。序列化时,需要实现Serializable接口。
下面还是以Book为例,看下深复制的一般实现过程:
1.定义Book类和Author类(注意:不仅Book类需要实现Serializable接口,Author同样也需要实现Serializable接口!!):
2.测试:
从输出结果中可以看出,深复制不仅在堆内存上开辟了空间以存储复制出的对象,甚至连对象中的引用类型的属性所指向的对象也得以复制,重新开辟了堆空间存储。
至此:设计模式中的创建型模式总结完毕,一共有五种创建型模式,分别为:单例模式(SingleTon)、建造者模式(Builder)、工厂方法模式(Factory Method)、抽象工厂模式(Abstract Factory)和原型模式(Prototype)。每种模式适用于不同的场景,具体应用时需注意区分。
在理解Java原型模式之前,首先需要理解Java中的一个概念:复制/克隆。
在博文《Java总结篇系列:java.lang.Object》一文中,对Java中的clone()方法进行了一定的阐述。同时,我们需要知道,Java中的对象复制/克隆分为浅复制和深复制。
一、浅复制:
我们知道,一个类的定义中包括属性和方法。属性用于表示对象的状态,方法用于表示对象所具有的行为。其中,属性既可以是Java中基本数据类型,也可以是引用类型。Java中的浅复制通常使用clone()方式完成。
当进浅复制时,clone函数返回的是一个引用,指向的是新的clone出来的对象,此对象与原对象分别占用不同的堆空间。同时,复制出来的对象具有与原对象一致的状态。
此处对象一致的状态是指:复制出的对象与原对象中的属性值完全相等==。
下面以复制一本书为例:
1.定义Book类和Author类:
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; } }
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) { // TODO Auto-generated catch block 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; } }
2.测试:
package com.qqyumidi; public class PrototypeTest { public static void main(String[] args) { Book book1 = new Book(); Author author = new Author(); author.setName("corn"); author.setAge(100); book1.setAuthor(author); book1.setTitle("好记性不如烂博客"); book1.setPageNum(230); Book book2 = book1.clone(); System.out.println(book1 == book2); // false System.out.println(book1.getPageNum() == book2.getPageNum()); // true System.out.println(book1.getTitle() == book2.getTitle()); // true System.out.println(book1.getAuthor() == book2.getAuthor()); // true } }
由输出的结果可以验证说到的结论。由此我们发现:虽然复制出来的对象重新在堆上开辟了内存空间,但是,对象中各属性确保持相等。对于基本数据类型很好理解,但对于引用数据类型来说,则意味着此引用类型的属性所指向的对象本身是相同的, 并没有重新开辟内存空间存储。换句话说,引用类型的属性所指向的对象并没有复制。
由此,我们将其称之为浅复制。当复制后的对象的引用类型的属性所指向的对象也重新得以复制,此时,称之为深复制。
二、深复制:
Java中的深复制一般是通过对象的序列化和反序列化得以实现。序列化时,需要实现Serializable接口。
下面还是以Book为例,看下深复制的一般实现过程:
1.定义Book类和Author类(注意:不仅Book类需要实现Serializable接口,Author同样也需要实现Serializable接口!!):
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; } }
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; } }
2.测试:
public class PrototypeTest { public static void main(String[] args) throws ClassNotFoundException, IOException { Book book1 = new Book(); Author author = new Author(); author.setName("corn"); author.setAge(100); book1.setAuthor(author); book1.setTitle("好记性不如烂博客"); book1.setPageNum(230); Book book2 = book1.deepClone(); System.out.println(book1 == book2); // false System.out.println(book1.getPageNum() == book2.getPageNum()); // true System.out.println(book1.getTitle() == book2.getTitle()); // false System.out.println(book1.getAuthor() == book2.getAuthor()); // false } }
从输出结果中可以看出,深复制不仅在堆内存上开辟了空间以存储复制出的对象,甚至连对象中的引用类型的属性所指向的对象也得以复制,重新开辟了堆空间存储。
至此:设计模式中的创建型模式总结完毕,一共有五种创建型模式,分别为:单例模式(SingleTon)、建造者模式(Builder)、工厂方法模式(Factory Method)、抽象工厂模式(Abstract Factory)和原型模式(Prototype)。每种模式适用于不同的场景,具体应用时需注意区分。
相关文章推荐
- 设计模式学习总结4 - 创建型4 - Prototype原型模式
- 设计模式学习系列6 原型模式(prototype)
- 菜鸟学设计模式系列笔记之Prototype模式(原型模式)
- 设计模式总结之Prototype Pattern(原型模式)
- 设计模式系列学习四:原型模式(Prototype)
- C#设计模式之原型(ProtoType)
- 设计模式之Prototype(原型)
- 设计模式学习笔记(四)——Prototype原型
- 设计模式就是来解决应变---原型(prototype)
- C#设计模式之原型(ProtoType)
- 设计模式学习笔记(六)——Prototype原型模式
- 设计模式(3)-原型模式(Prototype)
- C#设计模式之原型(ProtoType)
- 设计模式学习笔记(六)——Prototype原型模式
- java设计模式---prototype(原型)模式
- 用Java实现的设计模式系列(2)-Prototype
- 设计模式PHP5实现之----原型(Prototype)
- C#设计模式之原型(ProtoType)
- 设计模式之Prototype(原型)
- 设计模式与泡mm的关系之Prototype原型模式及原型模式的再思考