<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      設計模式-day02

      # 4,創(chuàng)建型模式

      4.2 工廠模式

      4.2.1 概述

      需求:設計一個咖啡店點餐系統(tǒng)。

      設計一個咖啡類(Coffee),并定義其兩個子類(美式咖啡【AmericanCoffee】和拿鐵咖啡【LatteCoffee】);再設計一個咖啡店類(CoffeeStore),咖啡店具有點咖啡的功能。

      具體類的設計如下:

      在java中,萬物皆對象,這些對象都需要創(chuàng)建,如果創(chuàng)建的時候直接new該對象,就會對該對象耦合嚴重,假如我們要更換對象,所有new對象的地方都需要修改一遍,這顯然違背了軟件設計的開閉原則。如果我們使用工廠來生產(chǎn)對象,我們就只和工廠打交道就可以了,徹底和對象解耦,如果要更換對象,直接在工廠里更換該對象即可,達到了與對象解耦的目的;所以說,工廠模式最大的優(yōu)點就是:解耦

      在本教程中會介紹三種工廠的使用

      • 簡單工廠模式(不屬于GOF的23種經(jīng)典設計模式)
      • 工廠方法模式
      • 抽象工廠模式

      4.2.2 簡單工廠模式

      簡單工廠不是一種設計模式,反而比較像是一種編程習慣。

      4.2.2.1 結構

      簡單工廠包含如下角色:

      • 抽象產(chǎn)品 :定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能。
      • 具體產(chǎn)品 :實現(xiàn)或者繼承抽象產(chǎn)品的子類
      • 具體工廠 :提供了創(chuàng)建產(chǎn)品的方法,調用者通過該方法來獲取產(chǎn)品。

      4.2.2.2 實現(xiàn)

      現(xiàn)在使用簡單工廠對上面案例進行改進,類圖如下:

      工廠類代碼如下:

      public class SimpleCoffeeFactory {
      
          public Coffee createCoffee(String type) {
              Coffee coffee = null;
              if("americano".equals(type)) {
                  coffee = new AmericanoCoffee();
              } else if("latte".equals(type)) {
                  coffee = new LatteCoffee();
              }
              return coffee;
          }
      }
      

      工廠(factory)處理創(chuàng)建對象的細節(jié),一旦有了SimpleCoffeeFactory,CoffeeStore類中的orderCoffee()就變成此對象的客戶,后期如果需要Coffee對象直接從工廠中獲取即可。這樣也就解除了和Coffee實現(xiàn)類的耦合,同時又產(chǎn)生了新的耦合,CoffeeStore對象和SimpleCoffeeFactory工廠對象的耦合,工廠對象和商品對象的耦合。

      后期如果再加新品種的咖啡,我們勢必要需求修改SimpleCoffeeFactory的代碼,違反了開閉原則。工廠類的客戶端可能有很多,比如創(chuàng)建美團外賣等,這樣只需要修改工廠類的代碼,省去其他的修改操作。

      4.2.2.4 優(yōu)缺點

      優(yōu)點:

      封裝了創(chuàng)建對象的過程,可以通過參數(shù)直接獲取對象。把對象的創(chuàng)建和業(yè)務邏輯層分開,這樣以后就避免了修改客戶代碼,如果要實現(xiàn)新產(chǎn)品直接修改工廠類,而不需要在原代碼中修改,這樣就降低了客戶代碼修改的可能性,更加容易擴展。

      缺點:

      增加新產(chǎn)品時還是需要修改工廠類的代碼,違背了“開閉原則”。

      4.2.2.3 擴展

      靜態(tài)工廠

      在開發(fā)中也有一部分人將工廠類中的創(chuàng)建對象的功能定義為靜態(tài)的,這個就是靜態(tài)工廠模式,它也不是23種設計模式中的。代碼如下:

      public class SimpleCoffeeFactory {
      
          public static Coffee createCoffee(String type) {
              Coffee coffee = null;
              if("americano".equals(type)) {
                  coffee = new AmericanoCoffee();
              } else if("latte".equals(type)) {
                  coffee = new LatteCoffee();
              }
              return coffe;
          }
      }
      

      4.2.3 工廠方法模式

      針對上例中的缺點,使用工廠方法模式就可以完美的解決,完全遵循開閉原則。

      4.2.3.1 概念

      定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪個產(chǎn)品類對象。工廠方法使一個產(chǎn)品類的實例化延遲到其工廠的子類。

      4.2.3.2 結構

      工廠方法模式的主要角色:

      • 抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口,調用者通過它訪問具體工廠的工廠方法來創(chuàng)建產(chǎn)品。
      • 具體工廠(ConcreteFactory):主要是實現(xiàn)抽象工廠中的抽象方法,完成具體產(chǎn)品的創(chuàng)建。
      • 抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能。
      • 具體產(chǎn)品(ConcreteProduct):實現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來創(chuàng)建,它同具體工廠之間一一對應。

      4.2.3.3 實現(xiàn)

      使用工廠方法模式對上例進行改進,類圖如下:

      代碼如下:

      抽象工廠:

      public interface CoffeeFactory {
      
          Coffee createCoffee();
      }
      

      具體工廠:

      public class LatteCoffeeFactory implements CoffeeFactory {
      
          public Coffee createCoffee() {
              return new LatteCoffee();
          }
      }
      
      public class AmericanCoffeeFactory implements CoffeeFactory {
      
          public Coffee createCoffee() {
              return new AmericanCoffee();
          }
      }
      

      咖啡店類:

      public class CoffeeStore {
      
          private CoffeeFactory factory;
      
          public CoffeeStore(CoffeeFactory factory) {
              this.factory = factory;
          }
      
          public Coffee orderCoffee(String type) {
              Coffee coffee = factory.createCoffee();
              coffee.addMilk();
              coffee.addsugar();
              return coffee;
          }
      }
      

      從以上的編寫的代碼可以看到,要增加產(chǎn)品類時也要相應地增加工廠類,不需要修改工廠類的代碼了,這樣就解決了簡單工廠模式的缺點。

      工廠方法模式是簡單工廠模式的進一步抽象。由于使用了多態(tài)性,工廠方法模式保持了簡單工廠模式的優(yōu)點,而且克服了它的缺點。

      4.2.3.4 優(yōu)缺點

      優(yōu)點:

      • 用戶只需要知道具體工廠的名稱就可得到所要的產(chǎn)品,無須知道產(chǎn)品的具體創(chuàng)建過程;
      • 在系統(tǒng)增加新的產(chǎn)品時只需要添加具體產(chǎn)品類和對應的具體工廠類,無須對原工廠進行任何修改,滿足開閉原則;

      缺點:

      • 每增加一個產(chǎn)品就要增加一個具體產(chǎn)品類和一個對應的具體工廠類,這增加了系統(tǒng)的復雜度。

      4.2.4 抽象工廠模式

      前面介紹的工廠方法模式中考慮的是一類產(chǎn)品的生產(chǎn),如畜牧場只養(yǎng)動物、電視機廠只生產(chǎn)電視機、傳智播客只培養(yǎng)計算機軟件專業(yè)的學生等。

      這些工廠只生產(chǎn)同種類產(chǎn)品,同種類產(chǎn)品稱為同等級產(chǎn)品,也就是說:工廠方法模式只考慮生產(chǎn)同等級的產(chǎn)品,但是在現(xiàn)實生活中許多工廠是綜合型的工廠,能生產(chǎn)多等級(種類) 的產(chǎn)品,如電器廠既生產(chǎn)電視機又生產(chǎn)洗衣機或空調,大學既有軟件專業(yè)又有生物專業(yè)等。

      本節(jié)要介紹的抽象工廠模式將考慮多等級產(chǎn)品的生產(chǎn),將同一個具體工廠所生產(chǎn)的位于不同等級的一組產(chǎn)品稱為一個產(chǎn)品族,下圖所示橫軸是產(chǎn)品等級,也就是同一類產(chǎn)品;縱軸是產(chǎn)品族,也就是同一品牌的產(chǎn)品,同一品牌的產(chǎn)品產(chǎn)自同一個工廠。

      4.2.4.1 概念

      是一種為訪問類提供一個創(chuàng)建一組相關或相互依賴對象的接口,且訪問類無須指定所要產(chǎn)品的具體類就能得到同族的不同等級的產(chǎn)品的模式結構。

      抽象工廠模式是工廠方法模式的升級版本,工廠方法模式只生產(chǎn)一個等級的產(chǎn)品,而抽象工廠模式可生產(chǎn)多個等級的產(chǎn)品。

      4.2.4.2 結構

      抽象工廠模式的主要角色如下:

      • 抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口,它包含多個創(chuàng)建產(chǎn)品的方法,可以創(chuàng)建多個不同等級的產(chǎn)品。
      • 具體工廠(Concrete Factory):主要是實現(xiàn)抽象工廠中的多個抽象方法,完成具體產(chǎn)品的創(chuàng)建。
      • 抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能,抽象工廠模式有多個抽象產(chǎn)品。
      • 具體產(chǎn)品(ConcreteProduct):實現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來創(chuàng)建,它 同具體工廠之間是多對一的關系。

      4.2.4.2 實現(xiàn)

      現(xiàn)咖啡店業(yè)務發(fā)生改變,不僅要生產(chǎn)咖啡還要生產(chǎn)甜點,如提拉米蘇、抹茶慕斯等,要是按照工廠方法模式,需要定義提拉米蘇類、抹茶慕斯類、提拉米蘇工廠、抹茶慕斯工廠、甜點工廠類,很容易發(fā)生類爆炸情況。其中拿鐵咖啡、美式咖啡是一個產(chǎn)品等級,都是咖啡;提拉米蘇、抹茶慕斯也是一個產(chǎn)品等級;拿鐵咖啡和提拉米蘇是同一產(chǎn)品族(也就是都屬于意大利風味),美式咖啡和抹茶慕斯是同一產(chǎn)品族(也就是都屬于美式風味)。所以這個案例可以使用抽象工廠模式實現(xiàn)。類圖如下:

      代碼如下:

      抽象工廠:

      public interface DessertFactory {
      
          Coffee createCoffee();
      
          Dessert createDessert();
      }
      

      具體工廠:

      //美式甜點工廠
      public class AmericanDessertFactory implements DessertFactory {
      
          public Coffee createCoffee() {
              return new AmericanCoffee();
          }
      
          public Dessert createDessert() {
              return new MatchaMousse();
          }
      }
      //意大利風味甜點工廠
      public class ItalyDessertFactory implements DessertFactory {
      
          public Coffee createCoffee() {
              return new LatteCoffee();
          }
      
          public Dessert createDessert() {
              return new Tiramisu();
          }
      }
      

      如果要加同一個產(chǎn)品族的話,只需要再加一個對應的工廠類即可,不需要修改其他的類。

      4.2.4.3 優(yōu)缺點

      優(yōu)點:

      當一個產(chǎn)品族中的多個對象被設計成一起工作時,它能保證客戶端始終只使用同一個產(chǎn)品族中的對象。

      缺點:

      當產(chǎn)品族中需要增加一個新的產(chǎn)品時,所有的工廠類都需要進行修改。

      4.2.4.4 使用場景

      • 當需要創(chuàng)建的對象是一系列相互關聯(lián)或相互依賴的產(chǎn)品族時,如電器工廠中的電視機、洗衣機、空調等。

      • 系統(tǒng)中有多個產(chǎn)品族,但每次只使用其中的某一族產(chǎn)品。如有人只喜歡穿某一個品牌的衣服和鞋。

      • 系統(tǒng)中提供了產(chǎn)品的類庫,且所有產(chǎn)品的接口相同,客戶端不依賴產(chǎn)品實例的創(chuàng)建細節(jié)和內部結構。

      如:輸入法換皮膚,一整套一起換。生成不同操作系統(tǒng)的程序。

      4.2.5 模式擴展

      簡單工廠+配置文件解除耦合

      可以通過工廠模式+配置文件的方式解除工廠對象和產(chǎn)品對象的耦合。在工廠類中加載配置文件中的全類名,并創(chuàng)建對象進行存儲,客戶端如果需要對象,直接進行獲取即可。

      第一步:定義配置文件

      為了演示方便,我們使用properties文件作為配置文件,名稱為bean.properties

      american=com.itheima.pattern.factory.config_factory.AmericanCoffee
      latte=com.itheima.pattern.factory.config_factory.LatteCoffee
      

      第二步:改進工廠類

      public class CoffeeFactory {
      
          private static Map<String,Coffee> map = new HashMap();
      
          static {
              Properties p = new Properties();
              InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");
              try {
                  p.load(is);
                  //遍歷Properties集合對象
                  Set<Object> keys = p.keySet();
                  for (Object key : keys) {
                      //根據(jù)鍵獲取值(全類名)
                      String className = p.getProperty((String) key);
                      //獲取字節(jié)碼對象
                      Class clazz = Class.forName(className);
                      Coffee obj = (Coffee) clazz.newInstance();
                      map.put((String)key,obj);
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
          public static Coffee createCoffee(String name) {
      
              return map.get(name);
          }
      }
      

      靜態(tài)成員變量用來存儲創(chuàng)建的對象(鍵存儲的是名稱,值存儲的是對應的對象),而讀取配置文件以及創(chuàng)建對象寫在靜態(tài)代碼塊中,目的就是只需要執(zhí)行一次。

      4.2.6 JDK源碼解析-Collection.iterator方法

      public class Demo {
          public static void main(String[] args) {
              List<String> list = new ArrayList<>();
              list.add("令狐沖");
              list.add("風清揚");
              list.add("任我行");
      
              //獲取迭代器對象
              Iterator<String> it = list.iterator();
              //使用迭代器遍歷
              while(it.hasNext()) {
                  String ele = it.next();
                  System.out.println(ele);
              }
          }
      }
      

      對上面的代碼大家應該很熟,使用迭代器遍歷集合,獲取集合中的元素。而單列集合獲取迭代器的方法就使用到了工廠方法模式。我們看通過類圖看看結構:

      Collection接口是抽象工廠類,ArrayList是具體的工廠類;Iterator接口是抽象商品類,ArrayList類中的Iter內部類是具體的商品類。在具體的工廠類中iterator()方法創(chuàng)建具體的商品類的對象。

      另:

      ? 1,DateForamt類中的getInstance()方法使用的是工廠模式;

      ? 2,Calendar類中的getInstance()方法使用的是工廠模式;

      4.3 原型模式

      4.3.1 概述

      用一個已經(jīng)創(chuàng)建的實例作為原型,通過復制該原型對象來創(chuàng)建一個和原型對象相同的新對象。

      4.3.2 結構

      原型模式包含如下角色:

      • 抽象原型類:規(guī)定了具體原型對象必須實現(xiàn)的的 clone() 方法。
      • 具體原型類:實現(xiàn)抽象原型類的 clone() 方法,它是可被復制的對象。
      • 訪問類:使用具體原型類中的 clone() 方法來復制新的對象。

      接口類圖如下:

      4.3.3 實現(xiàn)

      原型模式的克隆分為淺克隆和深克隆。

      淺克隆:創(chuàng)建一個新對象,新對象的屬性和原來對象完全相同,對于非基本類型屬性,仍指向原有屬性所指向的對象的內存地址。

      深克隆:創(chuàng)建一個新對象,屬性中引用的其他對象也會被克隆,不再指向原有對象地址。

      Java中的Object類中提供了 clone() 方法來實現(xiàn)淺克隆。 Cloneable 接口是上面的類圖中的抽象原型類,而實現(xiàn)了Cloneable接口的子實現(xiàn)類就是具體的原型類。代碼如下:

      Realizetype(具體的原型類):

      public class Realizetype implements Cloneable {
      
          public Realizetype() {
              System.out.println("具體的原型對象創(chuàng)建完成!");
          }
      
          @Override
          protected Realizetype clone() throws CloneNotSupportedException {
              System.out.println("具體原型復制成功!");
              return (Realizetype) super.clone();
          }
      }
      

      PrototypeTest(測試訪問類):

      public class PrototypeTest {
          public static void main(String[] args) throws CloneNotSupportedException {
              Realizetype r1 = new Realizetype();
              Realizetype r2 = r1.clone();
      
              System.out.println("對象r1和r2是同一個對象?" + (r1 == r2));
          }
      }
      

      4.3.4 案例

      用原型模式生成“三好學生”獎狀

      同一學校的“三好學生”獎狀除了獲獎人姓名不同,其他都相同,可以使用原型模式復制多個“三好學生”獎狀出來,然后在修改獎狀上的名字即可。

      類圖如下:

      代碼如下:

      //獎狀類
      public class Citation implements Cloneable {
          private String name;
      
          public void setName(String name) {
              this.name = name;
          }
      
          public String getName() {
              return (this.name);
          }
      
          public void show() {
              System.out.println(name + "同學:在2020學年第一學期中表現(xiàn)優(yōu)秀,被評為三好學生。特發(fā)此狀!");
          }
      
          @Override
          public Citation clone() throws CloneNotSupportedException {
              return (Citation) super.clone();
          }
      }
      
      //測試訪問類
      public class CitationTest {
          public static void main(String[] args) throws CloneNotSupportedException {
              Citation c1 = new Citation();
              c1.setName("張三");
      
              //復制獎狀
              Citation c2 = c1.clone();
              //將獎狀的名字修改李四
              c2.setName("李四");
      
              c1.show();
              c2.show();
          }
      }
      

      4.3.5 使用場景

      • 對象的創(chuàng)建非常復雜,可以使用原型模式快捷的創(chuàng)建對象。
      • 性能和安全要求比較高。

      4.3.6 擴展(深克隆)

      將上面的“三好學生”獎狀的案例中Citation類的name屬性修改為Student類型的屬性。代碼如下:

      //獎狀類
      public class Citation implements Cloneable {
          private Student stu;
      
          public Student getStu() {
              return stu;
          }
      
          public void setStu(Student stu) {
              this.stu = stu;
          }
      
          void show() {
              System.out.println(stu.getName() + "同學:在2020學年第一學期中表現(xiàn)優(yōu)秀,被評為三好學生。特發(fā)此狀!");
          }
      
          @Override
          public Citation clone() throws CloneNotSupportedException {
              return (Citation) super.clone();
          }
      }
      
      //學生類
      public class Student {
          private String name;
          private String address;
      
          public Student(String name, String address) {
              this.name = name;
              this.address = address;
          }
      
          public Student() {
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public String getAddress() {
              return address;
          }
      
          public void setAddress(String address) {
              this.address = address;
          }
      }
      
      //測試類
      public class CitationTest {
          public static void main(String[] args) throws CloneNotSupportedException {
      
              Citation c1 = new Citation();
              Student stu = new Student("張三", "西安");
              c1.setStu(stu);
      
              //復制獎狀
              Citation c2 = c1.clone();
              //獲取c2獎狀所屬學生對象
              Student stu1 = c2.getStu();
              stu1.setName("李四");
      
              //判斷stu對象和stu1對象是否是同一個對象
              System.out.println("stu和stu1是同一個對象?" + (stu == stu1));
      
              c1.show();
              c2.show();
          }
      }
      

      運行結果為:

      說明:

      ? stu對象和stu1對象是同一個對象,就會產(chǎn)生將stu1對象中name屬性值改為“李四”,兩個Citation(獎狀)對象中顯示的都是李四。這就是淺克隆的效果,對具體原型類(Citation)中的引用類型的屬性進行引用的復制。這種情況需要使用深克隆,而進行深克隆需要使用對象流。代碼如下:

      public class CitationTest1 {
          public static void main(String[] args) throws Exception {
              Citation c1 = new Citation();
              Student stu = new Student("張三", "西安");
              c1.setStu(stu);
      
              //創(chuàng)建對象輸出流對象
              ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\b.txt"));
              //將c1對象寫出到文件中
              oos.writeObject(c1);
              oos.close();
      
              //創(chuàng)建對象出入流對象
              ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\b.txt"));
              //讀取對象
              Citation c2 = (Citation) ois.readObject();
              //獲取c2獎狀所屬學生對象
              Student stu1 = c2.getStu();
              stu1.setName("李四");
      
              //判斷stu對象和stu1對象是否是同一個對象
              System.out.println("stu和stu1是同一個對象?" + (stu == stu1));
      
              c1.show();
              c2.show();
          }
      }
      

      運行結果為:

      注意:Citation類和Student類必須實現(xiàn)Serializable接口,否則會拋NotSerializableException異常。

      4.5 建造者模式

      4.4.1 概述

      將一個復雜對象的構建與表示分離,使得同樣的構建過程可以創(chuàng)建不同的表示。

      • 分離了部件的構造(由Builder來負責)和裝配(由Director負責)。 從而可以構造出復雜的對象。這個模式適用于:某個對象的構建過程復雜的情況。
      • 由于實現(xiàn)了構建和裝配的解耦。不同的構建器,相同的裝配,也可以做出不同的對象;相同的構建器,不同的裝配順序也可以做出不同的對象。也就是實現(xiàn)了構建算法、裝配算法的解耦,實現(xiàn)了更好的復用。
      • 建造者模式可以將部件和其組裝過程分開,一步一步創(chuàng)建一個復雜的對象。用戶只需要指定復雜對象的類型就可以得到該對象,而無須知道其內部的具體構造細節(jié)。

      4.4.2 結構

      建造者(Builder)模式包含如下角色:

      • 抽象建造者類(Builder):這個接口規(guī)定要實現(xiàn)復雜對象的那些部分的創(chuàng)建,并不涉及具體的部件對象的創(chuàng)建。

      • 具體建造者類(ConcreteBuilder):實現(xiàn) Builder 接口,完成復雜產(chǎn)品的各個部件的具體創(chuàng)建方法。在構造過程完成后,提供產(chǎn)品的實例。

      • 產(chǎn)品類(Product):要創(chuàng)建的復雜對象。

      • 指揮者類(Director):調用具體建造者來創(chuàng)建復雜對象的各個部分,在指導者中不涉及具體產(chǎn)品的信息,只負責保證對象各部分完整創(chuàng)建或按某種順序創(chuàng)建。

      類圖如下:

      4.4.3 實例

      創(chuàng)建共享單車

      生產(chǎn)自行車是一個復雜的過程,它包含了車架,車座等組件的生產(chǎn)。而車架又有碳纖維,鋁合金等材質的,車座有橡膠,真皮等材質。對于自行車的生產(chǎn)就可以使用建造者模式。

      這里Bike是產(chǎn)品,包含車架,車座等組件;Builder是抽象建造者,MobikeBuilder和OfoBuilder是具體的建造者;Director是指揮者。類圖如下:

      具體的代碼如下:

      //自行車類
      public class Bike {
          private String frame;
          private String seat;
      
          public String getFrame() {
              return frame;
          }
      
          public void setFrame(String frame) {
              this.frame = frame;
          }
      
          public String getSeat() {
              return seat;
          }
      
          public void setSeat(String seat) {
              this.seat = seat;
          }
      }
      
      // 抽象 builder 類
      public abstract class Builder {
      
          protected Bike mBike = new Bike();
      
          public abstract void buildFrame();
          public abstract void buildSeat();
          public abstract Bike createBike();
      }
      
      //摩拜單車Builder類
      public class MobikeBuilder extends Builder {
      
          @Override
          public void buildFrame() {
              mBike.setFrame("鋁合金車架");
          }
      
          @Override
          public void buildSeat() {
              mBike.setSeat("真皮車座");
          }
      
          @Override
          public Bike createBike() {
              return mBike;
          }
      }
      
      //ofo單車Builder類
      public class OfoBuilder extends Builder {
      
          @Override
          public void buildFrame() {
              mBike.setFrame("碳纖維車架");
          }
      
          @Override
          public void buildSeat() {
              mBike.setSeat("橡膠車座");
          }
      
          @Override
          public Bike createBike() {
              return mBike;
          }
      }
      
      //指揮者類
      public class Director {
          private Builder mBuilder;
      
          public Director(Builder builder) {
              mBuilder = builder;
          }
      
          public Bike construct() {
              mBuilder.buildFrame();
              mBuilder.buildSeat();
              return mBuilder.createBike();
          }
      }
      
      //測試類
      public class Client {
          public static void main(String[] args) {
              showBike(new OfoBuilder());
              showBike(new MobikeBuilder());
          }
          private static void showBike(Builder builder) {
              Director director = new Director(builder);
              Bike bike = director.construct();
              System.out.println(bike.getFrame());
              System.out.println(bike.getSeat());
          }
      }
      

      注意:

      上面示例是 Builder模式的常規(guī)用法,指揮者類 Director 在建造者模式中具有很重要的作用,它用于指導具體構建者如何構建產(chǎn)品,控制調用先后次序,并向調用者返回完整的產(chǎn)品類,但是有些情況下需要簡化系統(tǒng)結構,可以把指揮者類和抽象建造者進行結合

      // 抽象 builder 類
      public abstract class Builder {
      
          protected Bike mBike = new Bike();
      
          public abstract void buildFrame();
          public abstract void buildSeat();
          public abstract Bike createBike();
          
          public Bike construct() {
              this.buildFrame();
              this.BuildSeat();
              return this.createBike();
          }
      }
      

      說明:

      這樣做確實簡化了系統(tǒng)結構,但同時也加重了抽象建造者類的職責,也不是太符合單一職責原則,如果construct() 過于復雜,建議還是封裝到 Director 中。

      4.4.4 優(yōu)缺點

      優(yōu)點:

      • 建造者模式的封裝性很好。使用建造者模式可以有效的封裝變化,在使用建造者模式的場景中,一般產(chǎn)品類和建造者類是比較穩(wěn)定的,因此,將主要的業(yè)務邏輯封裝在指揮者類中對整體而言可以取得比較好的穩(wěn)定性。
      • 在建造者模式中,客戶端不必知道產(chǎn)品內部組成的細節(jié),將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對象。
      • 可以更加精細地控制產(chǎn)品的創(chuàng)建過程 。將復雜產(chǎn)品的創(chuàng)建步驟分解在不同的方法中,使得創(chuàng)建過程更加清晰,也更方便使用程序來控制創(chuàng)建過程。
      • 建造者模式很容易進行擴展。如果有新的需求,通過實現(xiàn)一個新的建造者類就可以完成,基本上不用修改之前已經(jīng)測試通過的代碼,因此也就不會對原有功能引入風險。符合開閉原則。

      缺點:

      造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點,其組成部分相似,如果產(chǎn)品之間的差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。

      4.4.5 使用場景

      建造者(Builder)模式創(chuàng)建的是復雜對象,其產(chǎn)品的各個部分經(jīng)常面臨著劇烈的變化,但將它們組合在一起的算法卻相對穩(wěn)定,所以它通常在以下場合使用。

      • 創(chuàng)建的對象較復雜,由多個部件構成,各部件面臨著復雜的變化,但構件間的建造順序是穩(wěn)定的。
      • 創(chuàng)建復雜對象的算法獨立于該對象的組成部分以及它們的裝配方式,即產(chǎn)品的構建過程和最終的表示是獨立的。

      4.4.6 模式擴展

      建造者模式除了上面的用途外,在開發(fā)中還有一個常用的使用方式,就是當一個類構造器需要傳入很多參數(shù)時,如果創(chuàng)建這個類的實例,代碼可讀性會非常差,而且很容易引入錯誤,此時就可以利用建造者模式進行重構。

      重構前代碼如下:

      public class Phone {
          private String cpu;
          private String screen;
          private String memory;
          private String mainboard;
      
          public Phone(String cpu, String screen, String memory, String mainboard) {
              this.cpu = cpu;
              this.screen = screen;
              this.memory = memory;
              this.mainboard = mainboard;
          }
      
          public String getCpu() {
              return cpu;
          }
      
          public void setCpu(String cpu) {
              this.cpu = cpu;
          }
      
          public String getScreen() {
              return screen;
          }
      
          public void setScreen(String screen) {
              this.screen = screen;
          }
      
          public String getMemory() {
              return memory;
          }
      
          public void setMemory(String memory) {
              this.memory = memory;
          }
      
          public String getMainboard() {
              return mainboard;
          }
      
          public void setMainboard(String mainboard) {
              this.mainboard = mainboard;
          }
      
          @Override
          public String toString() {
              return "Phone{" +
                      "cpu='" + cpu + '\'' +
                      ", screen='" + screen + '\'' +
                      ", memory='" + memory + '\'' +
                      ", mainboard='" + mainboard + '\'' +
                      '}';
          }
      }
      
      public class Client {
          public static void main(String[] args) {
              //構建Phone對象
              Phone phone = new Phone("intel","三星屏幕","金士頓","華碩");
              System.out.println(phone);
          }
      }
      

      上面在客戶端代碼中構建Phone對象,傳遞了四個參數(shù),如果參數(shù)更多呢?代碼的可讀性及使用的成本就是比較高。

      重構后代碼:

      public class Phone {
      
          private String cpu;
          private String screen;
          private String memory;
          private String mainboard;
      
          private Phone(Builder builder) {
              cpu = builder.cpu;
              screen = builder.screen;
              memory = builder.memory;
              mainboard = builder.mainboard;
          }
      
          public static final class Builder {
              private String cpu;
              private String screen;
              private String memory;
              private String mainboard;
      
              public Builder() {}
      
              public Builder cpu(String val) {
                  cpu = val;
                  return this;
              }
              public Builder screen(String val) {
                  screen = val;
                  return this;
              }
              public Builder memory(String val) {
                  memory = val;
                  return this;
              }
              public Builder mainboard(String val) {
                  mainboard = val;
                  return this;
              }
              public Phone build() {
                  return new Phone(this);}
          }
          @Override
          public String toString() {
              return "Phone{" +
                      "cpu='" + cpu + '\'' +
                      ", screen='" + screen + '\'' +
                      ", memory='" + memory + '\'' +
                      ", mainboard='" + mainboard + '\'' +
                      '}';
          }
      }
      
      public class Client {
          public static void main(String[] args) {
              Phone phone = new Phone.Builder()
                      .cpu("intel")
                      .mainboard("華碩")
                      .memory("金士頓")
                      .screen("三星")
                      .build();
              System.out.println(phone);
          }
      }
      

      重構后的代碼在使用起來更方便,某種程度上也可以提高開發(fā)效率。從軟件設計上,對程序員的要求比較高。

      4.6 創(chuàng)建者模式對比

      4.6.1 工廠方法模式VS建造者模式

      工廠方法模式注重的是整體對象的創(chuàng)建方式;而建造者模式注重的是部件構建的過程,意在通過一步一步地精確構造創(chuàng)建出一個復雜的對象。

      我們舉個簡單例子來說明兩者的差異,如要制造一個超人,如果使用工廠方法模式,直接產(chǎn)生出來的就是一個力大無窮、能夠飛翔、內褲外穿的超人;而如果使用建造者模式,則需要組裝手、頭、腳、軀干等部分,然后再把內褲外穿,于是一個超人就誕生了。

      4.6.2 抽象工廠模式VS建造者模式

      抽象工廠模式實現(xiàn)對產(chǎn)品家族的創(chuàng)建,一個產(chǎn)品家族是這樣的一系列產(chǎn)品:具有不同分類維度的產(chǎn)品組合,采用抽象工廠模式則是不需要關心構建過程,只關心什么產(chǎn)品由什么工廠生產(chǎn)即可。

      建造者模式則是要求按照指定的藍圖建造產(chǎn)品,它的主要目的是通過組裝零配件而產(chǎn)生一個新產(chǎn)品。

      如果將抽象工廠模式看成汽車配件生產(chǎn)工廠,生產(chǎn)一個產(chǎn)品族的產(chǎn)品,那么建造者模式就是一個汽車組裝工廠,通過對部件的組裝可以返回一輛完整的汽車。

      posted @ 2023-07-13 07:42  起跑線小言  閱讀(27)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 野花香视频在线观看免费高清版| 青草成人精品视频在线看| 亚洲成人av在线资源网| 99中文字幕国产精品| 久久久精品94久久精品| 日韩精品一区二区在线看| 亚洲中文一区二区av| 亚洲第一极品精品无码久久| 国产裸体无遮挡免费精品| 欧美和黑人xxxx猛交视频| 国产亚洲av嫩草久久| 国产日韩综合av在线| 国产360激情盗摄全集| 丁香五月婷激情综合第九色| 国产精品看高国产精品不卡| 亚洲熟妇自偷自拍另欧美| 精品中文人妻在线不卡| 亚洲免费观看视频| 午夜精品极品粉嫩国产尤物| 精品国产免费一区二区三区香蕉| 色爱无码av综合区| 国内揄拍国内精品少妇国语 | 97久久综合亚洲色hezyo| 狠狠色丁香婷婷综合| 国产精品一区二区国产馆| 国产精品中文字幕二区| 国产成人免费ā片在线观看| 国产亚洲精品精品精品| 国产精品成人中文字幕| 色综合久久一区二区三区| 亚洲人精品午夜射精日韩| 精品久久人人做爽综合| 通许县| 免费人成视频网站在线观看18| 精品综合一区二区三区四区 | 一级女性全黄久久片免费| 欧美成人精品手机在线| 久久亚洲国产精品久久| 999精品色在线播放| 国产福利免费在线观看| 日韩丝袜欧美人妻制服|