原型模式

落日映苍穹つ 2021-12-05 01:03 301阅读 0赞

原型模式(Prototype Pattern):通过原型实例指定创建对象的种类,并且通过克隆这些原型来创建新的对象。原型模式是一种创建型模式

完成原型模式一般需要3个角色,抽象原型类、具体原型类、客户类

抽象原型类:声明克隆方法的接口、抽象类或具体实现类。是所有具体原型类的公共父类

具体原型类:实现抽象原型类,实现抽象原型类中的克隆方法,并在克隆方法中返回自己的一个克隆对象

客户类:通过原型对象克隆自己创建新的对象

实例代码如下

定义抽象原型类,声明克隆方法

  1. package com.design.prototype;
  2. /**
  3. * 抽象原型类
  4. */
  5. public interface Prototype {
  6. //声明克隆方法
  7. Prototype clone();
  8. }

定义具体原型类,实现抽象原型类,实现克隆方法

  1. package com.design.prototype;
  2. /**
  3. * 具体原型类
  4. */
  5. public class ConcretePrototype implements Prototype{
  6. private String name;
  7. public String getName() {
  8. return name;
  9. }
  10. public void setName(String name) {
  11. this.name = name;
  12. }
  13. @Override
  14. public Prototype clone() {
  15. Prototype prototype = new ConcretePrototype();
  16. ((ConcretePrototype) prototype).setName(this.name);
  17. return prototype;
  18. }
  19. @Override
  20. public String toString() {
  21. return "ConcretePrototype{" +
  22. "name='" + name + '\'' +
  23. '}' + super.toString();
  24. }
  25. }

定义客户类,调用测试

  1. package com.design.prototype;
  2. public class TestMain {
  3. public static void main(String[] args) {
  4. Prototype prototype = new ConcretePrototype();
  5. System.out.println(prototype);
  6. //克隆 prototype1 对象
  7. Prototype prototype1 = prototype.clone();
  8. System.out.println(prototype1);
  9. }
  10. }

上述示例代码可以作为原型模式的通用实现,与编程语言特性无关

下边来谈 java 语言实现原型模式

java 语言实现原型模式

使用 java 语言实现原型模式很简单。了解 java 语言的人都知道,在 java 语言中所有的类都继承自 java.lang.Object 类,而 Object 类提供了一个 clone()方法,可以将 java 对象进行克隆。因此,使用 java 语言实现原型模式可以不定义抽象原型类,直接使用 Object 类提供的 clone()方法实现对 java 对象的克隆

示例代码如下

定义书籍类

注意:要实现克隆的 java 类必须实现 Cloneable 接口,表示这个 java 类支持复制

这里的 clone() 方法直接使用了父类 Object 的 clone()方法

  1. package com.design.prototype.javaprototype;
  2. import java.util.Date;
  3. public class Book implements Cloneable{
  4. public Book(String bookName, String bookAuthor, Date date){
  5. this.bookName = bookName;
  6. this.bookAuthor = bookAuthor;
  7. this.date = date;
  8. }
  9. private String bookName;
  10. private String bookAuthor;
  11. private Date date;
  12. public String getBookName() {
  13. return bookName;
  14. }
  15. public void setBookName(String bookName) {
  16. this.bookName = bookName;
  17. }
  18. public String getBookAuthor() {
  19. return bookAuthor;
  20. }
  21. public void setBookAuthor(String bookAuthor) {
  22. this.bookAuthor = bookAuthor;
  23. }
  24. public Date getDate() {
  25. return date;
  26. }
  27. public void setDate(Date date) {
  28. this.date = date;
  29. }
  30. @Override
  31. protected Object clone() throws CloneNotSupportedException {
  32. return super.clone(); //浅克隆
  33. }
  34. @Override
  35. public String toString() {
  36. return "Book{" +
  37. "bookName='" + bookName + '\'' +
  38. ", bookAuthor='" + bookAuthor + '\'' +
  39. ", date=" + date +
  40. '}'+ super.toString();
  41. }
  42. }

测试调用

  1. package com.design.prototype.javaprototype;
  2. import java.util.Date;
  3. public class TestMain {
  4. public static void main(String[] args) throws CloneNotSupportedException {
  5. Book book = new Book("红楼梦", "曹雪芹", new Date());
  6. Book book1 = (Book) book.clone();
  7. System.out.println(book);
  8. System.out.println(book1);
  9. System.out.println(book == book1);
  10. System.out.println(book.getBookName() == book1.getBookName());
  11. }
  12. }

测试结果如下图

20190717164006791.png

通过打印出的结果可以看出,使用原型模式成功克隆出来 book1 对象

但是,如果仔细观察会发现 book 对象和 book1 对象的 bookName 属性的内存地址值完全相等,通过 debug 进一步分析

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dzanp6Y2Jx_size_16_color_FFFFFF_t_70

发现 book 对象和 book1 对象的属性确实指向了相同的内存地址,这里我们引入两个概念,浅克隆和深克隆

浅克隆:若原型对象的成员变量是值类型,则复制一份给克隆对象;若原型对象的成员变量是引用类型,则将引用对象的内存地址复制一份给克隆对象,即原型对象和克隆对象的成员变量都指向相同的内存地址。简单的讲,浅克隆只复制对象本身及其中包含的值类型的成员变量,引用类型的成员对象并没有被复制

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dzanp6Y2Jx_size_16_color_FFFFFF_t_70 1

深克隆:无论原型对象的成员变量是值类型还是引用类型,都复制一份给克隆对象

了解了浅克隆和深克隆的概念后,就知道上边的代码其实实现的是浅克隆的原型模式

下边代码演示深克隆的原型模式

这里自定义克隆方法

  1. package com.design.prototype.javaprototype;
  2. import java.io.*;
  3. import java.util.Date;
  4. public class DeepBook implements Serializable {
  5. public DeepBook(String bookName, String bookAuthor, Date date){
  6. this.bookName = bookName;
  7. this.bookAuthor = bookAuthor;
  8. this.date = date;
  9. }
  10. private String bookName;
  11. private String bookAuthor;
  12. private Date date;
  13. public String getBookName() {
  14. return bookName;
  15. }
  16. public void setBookName(String bookName) {
  17. this.bookName = bookName;
  18. }
  19. public String getBookAuthor() {
  20. return bookAuthor;
  21. }
  22. public void setBookAuthor(String bookAuthor) {
  23. this.bookAuthor = bookAuthor;
  24. }
  25. public Date getDate() {
  26. return date;
  27. }
  28. public void setDate(Date date) {
  29. this.date = date;
  30. }
  31. /**
  32. * 自定义深克隆方法
  33. * @return
  34. */
  35. public DeepBook clone(){
  36. DeepBook deepBook = null;
  37. try {
  38. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  39. ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
  40. objectOutputStream.writeObject(this);
  41. ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
  42. ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
  43. try {
  44. deepBook = (DeepBook) objectInputStream.readObject();
  45. } catch (ClassNotFoundException e) {
  46. e.printStackTrace();
  47. }
  48. } catch (IOException e) {
  49. e.printStackTrace();
  50. }
  51. return deepBook;
  52. }
  53. }

测试调用

  1. package com.design.prototype.javaprototype;
  2. import java.util.Date;
  3. public class TestMain {
  4. public static void main(String[] args) throws CloneNotSupportedException {
  5. DeepBook deepBook = new DeepBook("三国演义","罗贯中", new Date());
  6. DeepBook deepBook1 = deepBook.clone();
  7. System.out.println(deepBook.getBookName() == deepBook1.getBookName());
  8. }
  9. }

20190717174510700.png

控制台打印 false,说明实现了深克隆

原型模式总结

优点:创建新的较为复杂的对象时,使用原型模式可以简化创建过程;扩展性好;深克隆方式可以保存对象状态

缺点:因为每个类配备一个克隆方法,所以对已有的类进行改造时,违背了开闭原则;深克隆编写较为复杂的代码比较麻烦

适用场景:创建新的对象成本较大,通过原型模式复制得到可以减少资源占用;构造函数比较复杂;循环体中创建大量对象

发表评论

表情:
评论列表 (有 0 条评论,301人围观)

还没有评论,来说两句吧...

相关阅读

    相关 原型模式

    一. 原型模式简介    原型模式(Prototype Pattern)也是一种创建型模式,它关注的是大量相似对象的创建问题。我们经常会遇到这样的情况:在系统中要创建大量的

    相关 原型模式

    对象浅拷贝 实现Clonable接口,重写clone方法,jvm的本地方法实现拷贝 Object protected native Object clone()

    相关 原型模式

    原型模式(Prototype Pattern):通过原型实例指定创建对象的种类,并且通过克隆这些原型来创建新的对象。原型模式是一种创建型模式   完成原型模式一般需要3个角

    相关 原型模式

    原型模式:用原型实例指定创建指定对象的种类,并且通过复制这些原型创建新的对象,同时又能保证性能。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价

    相关 原型模式

    原型模式 定义 在软件系统中,有时需要多次创建某一类型的对象,为了简化创建过程,可以只创建一个对象,然后通过对象克隆的方式复制出多个相同的对象,这就是原型设计模

    相关 原型模式

    型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式是实现了...