设计模式之原型模式

一、什么原型模式

原型模式,用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。

二、原型模式角色

  • 抽象原型类:规定了具体原型对象必须实现的clone方法
  • 具体原型类:实现抽象原型类的clone方法,它是可被复制的对象。

三、原型模式实现方式

  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其它对象也会被克隆,不再指向原有对象地址。

四、原型模式优缺点

1、浅克隆

原型类需要实现JDK 的Cloneable接口的clone方法,客户端(调用者)只要调用clone方法即可复制一个新对象。

缺点:

对于原型类中的引用类型的成员属性被克隆后,仍指向原型对象的成员属性的地址,修改原型对象的属性值,将同时改变克隆对象对应的属性值。

2、深克隆

由于浅克隆存在的缺点,深克隆可以通过对象序列化后,再进行反序列化,就可以实现完全的克隆。原型类需要实现Serializable接口。

3、深克隆扩展

在实际工作中,深克隆场景还是比较多,但是实现深克隆主要借助于第三方工具包,性能和简便性都有保证,常见的如阿里巴巴的fastjson jar,原型类既不需要实现Cloneable接口,也不需要实现Serializable接口。

五、原型模式demo示例

1、浅克隆代码实现

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Author {
 
    //姓名
    private String name;
    //
    private int age;
    //住址
    private String address;
 
    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 String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    @Override
    public String toString() {
        return "Author{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", address='" + address + ''' +
                '}';
    }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class Book implements Cloneable {
 
     // 书名
     private String name;
     // 价格
     private Double price;
     // 出版日期
     private String publishDate;
     //作者
     // 引用类型
     private Author author;
  
     public String getName() {
         return name;
     }
  
     public void setName(String name) {
         this.name = name;
     }
  
     public Double getPrice() {
         return price;
     }
  
     public void setPrice(Double price) {
         this.price = price;
     }
  
     public String getPublishDate() {
         return publishDate;
     }
  
     public void setPublishDate(String publishDate) {
         this.publishDate = publishDate;
     }
  
     public Author getAuthor() {
         return author;
     }
  
     public void setAuthor(Author author) {
         this.author = author;
     }
  
     /**
      * 克隆方法,调用该方法将复制一个新对象并返回
      * @return
      * @throws CloneNotSupportedException
      */     @Override
     public Book clone() throws CloneNotSupportedException {
         return (Book) super.clone();
     }
  
     @Override
     public String toString() {
         return "Book{" +
                 "name='" + name + ''' +
                 ", price=" + price +
                 ", publishDate='" + publishDate + ''' +
                 ", author=" + author +
                 '}';
     }
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class CloneClient {
 
     public static void main(String[] args) throws CloneNotSupportedException {
         Author author = new Author();
         author.setAddress("上海市青浦区");
         author.setAge(20);
         author.setName("胡大师");
         Book book = new Book();
         book.setAuthor(author);
         book.setName("Python");
         book.setPrice(88d);
         book.setPublishDate("2020-01-12");
         System.out.println("修改前,原型对象信息:"+book);
         //克隆出的新对象
         Book cloneBook = book.clone();
         System.out.println("修改前,克隆对象信息:"+cloneBook);
         System.out.println("原型对象和克隆对象的author引用同一个对象:"+(book.getAuthor() == cloneBook.getAuthor()));
         System.out.println("===================================");
         //修改原型对象的作者信息
         author.setName("胡大帅");
         author.setAge(30);
         author.setAddress("上海市闵行区");
         System.out.println("修改后,原型对象信息:"+book);
         System.out.println("修改后,克隆对象信息:"+cloneBook);
         System.out.println("原型对象和克隆对象的author引用同一个对象:"+(book.getAuthor() == cloneBook.getAuthor()));
     }
 }

控制台输出日志:

设计模式之原型模式插图

2、深克隆代码实现

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Author implements Serializable {
 
     //姓名
     private String name;
     //
     private int age;
     //住址
     private String address;
  
     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 String getAddress() {
         return address;
     }
  
     public void setAddress(String address) {
         this.address = address;
     }
  
     @Override
     public String toString() {
         return "Author{" +
                 "name='" + name + ''' +
                 ", age=" + age +
                 ", address='" + address + ''' +
                 '}';
     }
 }
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class Book implements Serializable {
 
     // 书名
     private String name;
     // 价格
     private Double price;
     // 出版日期
     private String publishDate;
     //作者
     // 引用类型
     private Author author;
  
     public String getName() {
         return name;
     }
  
     public void setName(String name) {
         this.name = name;
     }
  
     public Double getPrice() {
         return price;
     }
  
     public void setPrice(Double price) {
         this.price = price;
     }
  
     public String getPublishDate() {
         return publishDate;
     }
  
     public void setPublishDate(String publishDate) {
         this.publishDate = publishDate;
     }
  
     public Author getAuthor() {
         return author;
     }
  
     public void setAuthor(Author author) {
         this.author = author;
     }
  
     public Book clone(){
         try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/clone.txt"));) {
             oos.writeObject(this);
             oos.flush();
  
         } catch (Exception e) {
             e.printStackTrace();
         }
         try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/clone.txt"));) {
             Book o = (Book)ois.readObject();
             return o;
         } catch (Exception e) {
             e.printStackTrace();
         }
         return null;
     }
  
     @Override
     public String toString() {
         return "Book{" +
                 "name='" + name + ''' +
                 ", price=" + price +
                 ", publishDate='" + publishDate + ''' +
                 ", author=" + author +
                 '}';
     }
 }
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class DeepCloneClient {
  
     public static void main(String[] args) {
         Author author = new Author();
         author.setAddress("上海市青浦区");
         author.setAge(20);
         author.setName("胡大师");
         Book book = new Book();
         book.setAuthor(author);
         book.setName("Python");
         book.setPrice(88d);
         book.setPublishDate("2020-01-12");
         System.out.println("修改前,原型对象信息:"+book);
         //克隆出的新对象
         Book cloneBook = book.clone();
         System.out.println("修改前,克隆对象信息:"+cloneBook);
         System.out.println("原型对象和克隆对象的author指向不同地址:"+(book.getAuthor() == cloneBook.getAuthor()));
         System.out.println("===================================");
         //修改原型对象的作者信息
         author.setName("胡大帅");
         author.setAge(30);
         author.setAddress("上海市闵行区");
         System.out.println("修改后,原型对象信息:"+book);
         System.out.println("修改后,克隆对象信息:"+cloneBook);
         System.out.println("原型对象和克隆对象的author指向不同地址:"+(book.getAuthor() == cloneBook.getAuthor()));
     }
 }

控制台输出日志:

设计模式之原型模式插图2

3、深克隆扩展代码实现

通过maven引入依赖包:

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.75</version>
</dependency>
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class AliDeepCloneClient {
 
     public static void main(String[] args) {
         Author author = new Author("胡大帅",20,"上海");
         Book book = new Book("Java编程",99d,"2020-01-12",author);
         //使用JSON序列化为字符串
         String str = JSON.toJSONString(book);
         //再将字符串反序列化为对象
         Book cloneBook = JSON.parseObject(str, Book.class);
         System.out.println("修改前,原型对象信息="+book);
         System.out.println("修改前,克隆对象信息="+cloneBook);
         System.out.println("原型对象的author和克隆对象的author,指向地址="+(book.getAuthor() == cloneBook.getAuthor()));
         //修改原型对象的author值
         author.setAddress("黄浦区");
         author.setAge(35);
         System.out.println("修改后,原型对象信息="+book);
         System.out.println("修改后,克隆对象信息="+cloneBook);
     }
}

控制台输出日志:

设计模式之原型模式插图4

发表评论

欢迎阅读『设计模式之原型模式|Java、设计模式|Nick Tan-梓潼Blog』