zoukankan      html  css  js  c++  java
  • 设计模式总结篇系列:原型模式(Prototype)

    首先对原型模式进行一个简单概念说明:通过一个已经存在的对象,复制出更多的具有与此对象具有相同类型的新的对象。

    在理解Java原型模式之前,首先需要理解Java中的一个概念:复制/克隆。

    在博文《Java总结篇系列:java.lang.Object》一文中,对Java中的clone()方法进行了一定的阐述。同时,我们需要知道,Java中的对象复制/克隆分为浅复制和深复制。

    一、浅复制:

    我们知道,一个类的定义中包括属性和方法。属性用于表示对象的状态,方法用于表示对象所具有的行为。其中,属性既可以是Java中基本数据类型,也可以是引用类型。Java中的浅复制通常使用clone()方式完成。

    当进浅复制时,clone函数返回的是一个引用,指向的是新的clone出来的对象,此对象与原对象分别占用不同的堆空间。同时,复制出来的对象具有与原对象一致的状态。

    此处对象一致的状态是指:复制出的对象与原对象中的属性值完全相等==。

    下面以复制一本书为例:

    1.定义Book类和Author类:

     1 class Author {
     2 
     3     private String name;
     4     private int age;
     5 
     6     public String getName() {
     7         return name;
     8     }
     9 
    10     public void setName(String name) {
    11         this.name = name;
    12     }
    13 
    14     public int getAge() {
    15         return age;
    16     }
    17 
    18     public void setAge(int age) {
    19         this.age = age;
    20     }
    21 
    22 }
     1 class Book implements Cloneable {
     2 
     3     private String title;
     4     private int pageNum;
     5     private Author author;
     6 
     7     public Book clone() {
     8         Book book = null;
     9         try {
    10             book = (Book) super.clone();
    11         } catch (CloneNotSupportedException e) {
    12             // TODO Auto-generated catch block
    13             e.printStackTrace();
    14         }
    15         return book;
    16     }
    17 
    18     public String getTitle() {
    19         return title;
    20     }
    21 
    22     public void setTitle(String title) {
    23         this.title = title;
    24     }
    25 
    26     public int getPageNum() {
    27         return pageNum;
    28     }
    29 
    30     public void setPageNum(int pageNum) {
    31         this.pageNum = pageNum;
    32     }
    33 
    34     public Author getAuthor() {
    35         return author;
    36     }
    37 
    38     public void setAuthor(Author author) {
    39         this.author = author;
    40     }
    41 
    42 }

    2.测试:

     1 package com.qqyumidi;
     2 
     3 public class PrototypeTest {
     4 
     5     public static void main(String[] args) {
     6         Book book1 = new Book();
     7         Author author = new Author();
     8         author.setName("corn");
     9         author.setAge(100);
    10         book1.setAuthor(author);
    11         book1.setTitle("好记性不如烂博客");
    12         book1.setPageNum(230);
    13 
    14         Book book2 = book1.clone();
    15         
    16         System.out.println(book1 == book2);  // false
    17         System.out.println(book1.getPageNum() == book2.getPageNum());   // true
    18         System.out.println(book1.getTitle() == book2.getTitle());        // true
    19         System.out.println(book1.getAuthor() == book2.getAuthor());        // true
    20         
    21     }
    22 }

    由输出的结果可以验证说到的结论。由此我们发现:虽然复制出来的对象重新在堆上开辟了内存空间,但是,对象中各属性确保持相等。对于基本数据类型很好理解,但对于引用数据类型来说,则意味着此引用类型的属性所指向的对象本身是相同的, 并没有重新开辟内存空间存储。换句话说,引用类型的属性所指向的对象并没有复制。

    由此,我们将其称之为浅复制。当复制后的对象的引用类型的属性所指向的对象也重新得以复制,此时,称之为深复制。

     

     

    二、深复制:

     Java中的深复制一般是通过对象的序列化和反序列化得以实现。序列化时,需要实现Serializable接口。

    下面还是以Book为例,看下深复制的一般实现过程:

    1.定义Book类和Author类(注意:不仅Book类需要实现Serializable接口,Author同样也需要实现Serializable接口!!):

     1 class Author implements Serializable{
     2 
     3     private String name;
     4     private int age;
     5 
     6     public String getName() {
     7         return name;
     8     }
     9 
    10     public void setName(String name) {
    11         this.name = name;
    12     }
    13 
    14     public int getAge() {
    15         return age;
    16     }
    17 
    18     public void setAge(int age) {
    19         this.age = age;
    20     }
    21 
    22 }
     1 class Book implements Serializable {
     2 
     3     private String title;
     4     private int pageNum;
     5     private Author author;
     6 
     7     public Book deepClone() throws IOException, ClassNotFoundException{
     8         // 写入当前对象的二进制流 
     9         ByteArrayOutputStream bos = new ByteArrayOutputStream();  
    10         ObjectOutputStream oos = new ObjectOutputStream(bos);  
    11         oos.writeObject(this);
    12         
    13         // 读出二进制流产生的新对象  
    14         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());  
    15         ObjectInputStream ois = new ObjectInputStream(bis);  
    16         return (Book) ois.readObject();
    17     }
    18     
    19     public String getTitle() {
    20         return title;
    21     }
    22 
    23     public void setTitle(String title) {
    24         this.title = title;
    25     }
    26 
    27     public int getPageNum() {
    28         return pageNum;
    29     }
    30 
    31     public void setPageNum(int pageNum) {
    32         this.pageNum = pageNum;
    33     }
    34 
    35     public Author getAuthor() {
    36         return author;
    37     }
    38 
    39     public void setAuthor(Author author) {
    40         this.author = author;
    41     }
    42 
    43 }

    2.测试:

     1 public class PrototypeTest {
     2 
     3     public static void main(String[] args) throws ClassNotFoundException, IOException {
     4         Book book1 = new Book();
     5         Author author = new Author();
     6         author.setName("corn");
     7         author.setAge(100);
     8         book1.setAuthor(author);
     9         book1.setTitle("好记性不如烂博客");
    10         book1.setPageNum(230);
    11 
    12         Book book2 = book1.deepClone();
    13         
    14         System.out.println(book1 == book2);  // false
    15         System.out.println(book1.getPageNum() == book2.getPageNum());   // true
    16         System.out.println(book1.getTitle() == book2.getTitle());        // false
    17         System.out.println(book1.getAuthor() == book2.getAuthor());        // false
    18         
    19     }
    20 }

    从输出结果中可以看出,深复制不仅在堆内存上开辟了空间以存储复制出的对象,甚至连对象中的引用类型的属性所指向的对象也得以复制,重新开辟了堆空间存储。

    至此:设计模式中的创建型模式总结完毕,一共有五种创建型模式,分别为:单例模式(SingleTon)、建造者模式(Builder)、工厂方法模式(Factory Method)、抽象工厂模式(Abstract Factory)和原型模式(Prototype)。每种模式适用于不同的场景,具体应用时需注意区分。

  • 相关阅读:
    Cookie-Session
    Chrome浏览器的Timing分析
    K-means: 多次random initialization来避免bad局部最优
    K-means: optimization objective(最小化cost function来求相应的参数)
    unsupervised learning: K-means 算法
    unsupervised learning: clustering介绍
    SVM: 实际中使用SVM的一些问题
    SVM: 使用kernels(核函数)的整个SVM算法过程
    SVM: 用kernels(核函数)来定义新的features,避免使用多项式,高斯kernel
    SVM:从数学上分析为什么优化cost function会产生大距离(margin)分类器
  • 原文地址:https://www.cnblogs.com/lwbqqyumidi/p/3746821.html
Copyright © 2011-2022 走看看