<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【設(shè)計(jì)模式】原來這就是原型模式

          共 12016字,需瀏覽 25分鐘

           ·

          2022-07-09 02:57

          原型模式介紹

          概述

          原型模式顧名思義,就是基于原型來創(chuàng)建對(duì)象,用人話說就是一個(gè)對(duì)象的產(chǎn)生可以不由零起步,直接從一個(gè)已經(jīng)具備一定雛形的對(duì)象克隆,然后再修改為所需要的對(duì)象。顯而易見 ,原型模式屬于創(chuàng)建型模式

          使用場(chǎng)景

          如果對(duì)象的創(chuàng)建成本比較大,例如某個(gè)對(duì)象里面的數(shù)據(jù)需要訪問數(shù)據(jù)庫(kù)才能拿到;并且同一個(gè)類的不同對(duì)象之間差別不大(大部分字段都相同),這種場(chǎng)景下可以考慮使用原型模式達(dá)到提高程序性能的作用。

          我們可以通過一個(gè)業(yè)務(wù)場(chǎng)景來理解原型模式的應(yīng)用,設(shè)計(jì)一個(gè)學(xué)生類,學(xué)生類主要的成員變量有名字name,班級(jí)classId, needExtraCourse,以及所學(xué)的課程 course,其中course需要通過rpc調(diào)用查詢課程系統(tǒng)獲取,這個(gè)耗時(shí)100ms。如果用普通的方式為該類創(chuàng)建同一個(gè)班的4個(gè) 對(duì)象,如下所示:

          import java.util.ArrayList;
          import java.util.Date;
          import java.util.List;

          class Student{
              private String name;
              private Integer classId;

              //是否需要額外多選課程 
              private Boolean needExtraCourse = false;
              
              //所學(xué)課程,需要通過rpc調(diào)用查詢課程系統(tǒng),耗時(shí)100ms
              private List<String> course = new ArrayList<>();

              public Student(String name, Integer classId) throws InterruptedException {
                  this.name = name;
                  this.classId = classId;

                  //超時(shí)模擬rpc調(diào)用獲取課程信息初始化course
                  Thread.sleep(100);
                  course.add("語(yǔ)文");
                  course.add("數(shù)學(xué)");
                  course.add("英語(yǔ)");
              }
              
              //getter、setter、toString函數(shù)省略
          }

          public class PrototypeExample {
              public static void main(String[] args) throws InterruptedException {
                  long start =  new Date().getTime();
                  Student student1 = new Student("張三",  1);
                  Student student2 = new Student("李四",  1);
                  Student student3 = new Student("王五",  1);
                  Student student4 = new Student("趙六",  1);

                  long end =  new Date().getTime();
                  System.out.println("創(chuàng)建對(duì)象共花費(fèi)了時(shí)間:" + (end -start) + " ms");
              }
          }

          ******************【運(yùn)行結(jié)果】******************
          創(chuàng)建對(duì)象共花費(fèi)了時(shí)間:
          413 ms

          只是創(chuàng)建了4個(gè)對(duì)象就花費(fèi)了400多ms,這樣成本也太大了,其實(shí)對(duì)于一個(gè)班級(jí)的學(xué)生,不考慮額外選修課程的情況下(needExtraCourse = false),所學(xué)的課程應(yīng)該是完全一樣的。

          因此可以用到今天介紹的原型模式先用普通的方式創(chuàng)建一個(gè)對(duì)象,然后從創(chuàng)建的對(duì)象中克隆出其它對(duì)象,再修改其它對(duì)象的name字段即可。

          UML類圖

          UML 類圖也比較簡(jiǎn)單,只有兩個(gè)部分:

          • ? 1.Cloneable接口

          • ? 2.Student類,實(shí)現(xiàn)了Cloneable接口的原型對(duì)象,這個(gè)對(duì)象有個(gè)能力就是可以克隆自己。

          原型模式實(shí)現(xiàn)

          原型模式的實(shí)現(xiàn)方式有兩種:淺拷貝深拷貝。關(guān)于淺拷貝和深拷貝,可以閱讀詳解淺拷貝與深拷貝

          淺拷貝模式

          淺拷貝僅僅復(fù)制所考慮的對(duì)象,而不復(fù)制它所引用的對(duì)象。Object類提供的方法clone只是拷貝本對(duì)象 , 其對(duì)象內(nèi)部的數(shù)組、引用對(duì)象等都不拷貝,還是指向原生對(duì)象的內(nèi)部元素地址,下面是淺拷貝原型模式實(shí)現(xiàn)的代碼:

          //1原型類需實(shí)現(xiàn)Cloneable接口
          class Student 
          implements Cloneable{
              //Student類的其余部分和上面例子一樣
              ......................

              @Override
              public Object clone() throws CloneNotSupportedException {
                  return super.clone();
              }

          }

          public class PrototypeExample {
              public static void main(String[] args) throws InterruptedException, CloneNotSupportedException {
                  long start =  new Date().getTime();
                  Student student1 = new Student("張三",  1);

                  Student student2 = (Student) student1.clone();
                  student2.setName("李四");

                  Student student3 = (Student) student1.clone();
                  student3.setName("王五");

                  Student student4 = (Student) student1.clone();
                  student4.setName("趙六 ");

                  System.out.println("student1--->" + student1);
                  System.out.println("student2--->" + student2);
                  System.out.println("student3--->" + student3);
                  System.out.println("student4--->" + student4);

                  long end =  new Date().getTime();
                  System.out.println("創(chuàng)建對(duì)象共花費(fèi)了時(shí)間:" + (end -start) + " ms");


                  //趙六選修了課程美術(shù)
                  student4.setNeedExtraCourse(true);
                  student4.getCourse().add("美術(shù) ");
                  System.out.println("\n趙六選修美術(shù)課后:");
                  System.out.println("student1--->" + student1);
                  System.out.println("student2--->" + student2);
                  System.out.println("student3--->" + student3);
                  System.out.println("student4--->" + student4);
              }
          }
          ******************【運(yùn)行結(jié)果】******************
          student1--->Student{name='張三', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student2--->Student{name='李四', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student3--->Student{name='王五', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student4--->Student{name='趙六 ', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          創(chuàng)建對(duì)象共花費(fèi)了時(shí)間:
          130 ms

          趙六選修美術(shù)課后:
          student1--->Student{name='張三', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ), 
          美術(shù) ]}
          student2--->Student{name='李四', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ), 
          美術(shù) ]}
          student3--->Student{name='王五', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ), 
          美術(shù) ]}
          student4--->Student{name='趙六 ', classId=1, needExtraCourse=true, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ), 
          美術(shù) ]}

          可以看到,通過原型模式的方式,同樣是創(chuàng)建四個(gè)對(duì)象,只花了100多ms,大大的提高了程序性能。

          但是這里還存在一個(gè)小問題:趙六比較好學(xué),所以還選修了美術(shù),但是通過程序的運(yùn)行結(jié)果可以看到,明明只是趙六選修了美術(shù),但是其他三個(gè)同學(xué)的課表中也都出現(xiàn)了美術(shù)課 。這是因?yàn)闇\拷貝雖然產(chǎn)生了兩個(gè)完全不同的對(duì)象,但是對(duì)象中有對(duì)其他對(duì)象的引用(如這里的List)都指向同一個(gè)對(duì)象。

          為了解決這個(gè)問題,我們引入了深拷貝模式

          深拷貝模式

          深拷貝模式把要復(fù)制的對(duì)象所引用的對(duì)象都拷貝了一遍

          class Student implements Cloneable{
              //Student類的其余部分和上面例子一樣
              ......................
             
           @Override
              public Object clone() throws CloneNotSupportedException {
                  Object object = super.clone();
                  Student student = (Student)object;

                  List<String> newCourse = new ArrayList<>();
                  Iterator<String>  it = student.course.iterator();

                  while (it.hasNext()) {
                      newCourse.add(it.next());
                  }

                  student.course  = newCourse;
                  return object;
              }

          }

          public class PrototypeExample {
              public static void main(String[] args) throws InterruptedException, CloneNotSupportedException {
                  long start =  new Date().getTime();
                  Student student1 = new Student("張三",  1);

                  Student student2 = (Student) student1.clone();
                  student2.setName("李四");

                  Student student3 = (Student) student1.clone();
                  student3.setName("王五");

                  Student student4 = (Student) student1.clone();
                  student4.setName("趙六 ");

                  System.out.println("student1--->" + student1);
                  System.out.println("student2--->" + student2);
                  System.out.println("student3--->" + student3);
                  System.out.println("student4--->" + student4);

                  long end =  new Date().getTime();
                  System.out.println("創(chuàng)建對(duì)象共花費(fèi)了時(shí)間:" + (end -start) + " ms");


                  //趙六選修了課程美術(shù)
                  student4.setNeedExtraCourse(true);
                  student4.getCourse().add("美術(shù) ");
                  System.out.println("\n趙六選修美術(shù)課后:");
                  System.out.println("student1--->" + student1);
                  System.out.println("student2--->" + student2);
                  System.out.println("student3--->" + student3);
                  System.out.println("student4--->" + student4);
              }
          }

          ******************【運(yùn)行結(jié)果】******************
          student1--->Student{name='張三', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student2--->Student{name='李四', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student3--->Student{name='王五', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student4--->Student{name='趙六 ', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          創(chuàng)建對(duì)象共花費(fèi)了時(shí)間:
          135 ms

          趙六選修美術(shù)課后:
          student1--->Student{name='張三', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student2--->Student{name='李四', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student3--->Student{name='王五', classId=1, needExtraCourse=false, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ)]}
          student4--->Student{name='趙六 ', classId=1, needExtraCourse=true, course=[語(yǔ)文, 數(shù)學(xué), 英語(yǔ), 
          美術(shù) ]}

          以看到,深拷貝模式 ,修改一個(gè)對(duì)象的引用類型的成員不會(huì)再影響另外對(duì)象的該成員了。

          本文源碼地址:
          https://github.com/qinlizhong1/javaStudy/tree/master/DesignPattern/src/prototype

          本文示例代碼環(huán)境:
          操作系統(tǒng):macOs 12.1
          JDK版本:12.0.1
          maven版本: 3.8.4

          —  —

          歡迎關(guān)注↓↓↓
          發(fā)文不易,如有幫助,辛苦點(diǎn)贊和在看
          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线日本高清 | 国产福利精品在线播放 | 国产精品人妻无码八区牛牛 | 无码区一区二区 | 成人伊人综合网 |