主頁 > 軟體設計 > 設計模式——創建型設計模式

設計模式——創建型設計模式

2022-08-17 12:06:20 軟體設計

創建型設計模式

爭對物件/類創建時的優化

工廠方法模式(了解)

通過定義頂層抽象工廠類,通過繼承的方式,針對于每一個產品都提供一個工廠類用于創建,

情況:只適用于簡單物件,當我們需要生產許多個產品族的時候,這種模式就有點乏力了

創建物件不再使用傳統的new,而是創建一個工廠類,作為all物體類創建物件的一個封裝類,(避免了更改類名、構造方法時,需要修改大量的代碼)

簡單工廠模式:(不靈活,不建議)

不符合開閉原則,如果輸入沒有提前寫好的水果則就需要再添加每個類里的代碼

//水果抽象類
public abstract class Fruit {   
    private final String name;
    
    public Fruit(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return name+"@"+hashCode();   //列印一下當前水果名稱,還有物件的hashCode
    }
}

//水果物體類
public class Apple extends Fruit{   //蘋果,繼承自水果

    public Apple() {
        super("蘋果");
    }
}
public class Orange extends Fruit{  //橘子,也是繼承自水果
    public Orange() {
        super("橘子");
    }
}

//水果工廠
public class FruitFactory {
    /**
     * 這里就直接來一個靜態方法根據指定型別進行創建
     * @param type 水果型別
     * @return 對應的水果物件
     */
    public static Fruit getFruit(String type) {
        switch (type) {
            case "蘋果":
                return new Apple();
           	case "橘子":
                return new Orange();
            default:
                return null;
        }
    }
}

//主方法
public class Main {
    public static void main(String[] args) {
        Fruit fruit = FruitFactory.getFruit("橘子");   //直接問工廠要,而不是我們自己去創建
        System.out.println(fruit);
    }
}

工廠方法模式:通過范型靈活實作

如果新增了水果型別,直接創建一個新的工廠類就行,不需要修改之前已經撰寫好的內容,

缺點:一種水果就有一種新的工廠類,太多工廠類了

//水果抽象類
public abstract class Fruit {   
    private final String name;
    
    public Fruit(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return name+"@"+hashCode();   //列印一下當前水果名稱,還有物件的hashCode
    }
}

//水果工廠
public abstract class FruitFactory<T extends Fruit> {   //將水果工廠抽象為抽象類,添加泛型T由子類指定水果型別
    public abstract T getFruit();  //不同的水果工廠,通過此方法生產不同的水果
}

//Apple工廠
public class AppleFactory extends FruitFactory<Apple> {  //蘋果工廠,直接回傳Apple,一步到位
    @Override
    public Apple getFruit() {
        return new Apple();
    }
}

//主方法
public class Main {
    public static void main(String[] args) {
        test(new AppleFactory()::getFruit);   //比如我們現在要吃一個蘋果,那么就直接通過蘋果工廠來獲取蘋果
    }

    //此方法模擬吃掉一個水果
    private static void test(Supplier<Fruit> supplier){
        System.out.println(supplier.get()+" 被吃掉了,真好吃,");
    }
}

抽象工廠模式

情況:適用于有一系列產品的公司,

缺點:容易違背開閉原則,一旦增加了一種產品,此時就必須去修改抽象工廠的介面,這樣就涉及到抽象工廠類的以及所有子類的改變

舉例:

image

實際上這些產品都是成族出現的,比如小米的產品線上有小米12,小米平板等,華為的產品線上也有華為手機、華為平板,但是如果按照我們之前工廠方法模式來進行設計,那就需要單獨設計9個工廠來生產上面這些產品,顯然這樣就比較浪費時間的,

我們就可以使用抽象工廠模式,我們可以將多個產品,都放在一個工廠中進行生成,按不同的產品族進行劃分,比如小米,那么我就可以安排一個小米工廠,而這個工廠里面就可以生產整條產品線上的內容,包括小米手機、小米平板、小米路由等,

//工廠抽象類
public abstract class AbstractFactory {
    public abstract Phone getPhone();
    public abstract Table getTable();
    public abstract Router getRouter();
}

//工廠實作類
public class AbstractFactoryImpl extends AbstractFactory{
    @Override
    public Phone getPhone() {
        return new ProductPhone();
    }

    @Override
    public Table getTable() {
        return new ProductTable();
    }

    @Override
    public Router getRouter() {
        return new ProductRouter();
    }
}

//產品抽象類
public abstract class AbRouter{
    public abstract Router getRouter();
}
...
    
//產品物體類
public class Router extends AbRouter{
    
    @Override
    public Router getRouter(){
        return new Router();
    }
}

建造者模式

當構造物件時引數較多,可以通過建造者模式使用鏈式方法創建物件,保證引數填寫正確,

可以去看看StringBuilder的原始碼,有很多的框架都為我們提供了形如XXXBuilder的型別,我們一般也是使用這些類來創建我們需要的物件,

建造者模式創建物件其實和StringBuilder一樣:實際上我們是通過建造者來不斷配置引數或是內容,當我們配置完所有內容后,最后再進行物件的構建,

public static void main(String[] args) {
    StringBuilder builder = new StringBuilder();   //創建一個StringBuilder來逐步構建一個字串
    builder.append(666);   //拼接一個數字
    builder.append("老鐵");   //拼接一個字串
   	builder.insert(2, '?');  //在第三個位置插入一個字符
    System.out.println(builder.toString());   //差不多成形了,最后轉換為字串
}

舉例:

//物體類的撰寫
public class Student {
	int id;
    int age;
    int grade;
    String name;
    String college;
    String profession;
    List<String> awards;

    //一律使用建造者來創建,不對外直接開放
    private Student(int id, int age, int grade, String name, String college, String profession, List<String> awards) {
        this.id = id;
        this.age = age;
        this.grade = grade;
        this.name = name;
        this.college = college;
        this.profession = profession;
        this.awards = awards;
    }

    public static StudentBuilder builder(){   //通過builder方法直接獲取建造者
        return new StudentBuilder();
    }

    public static class StudentBuilder{   //這里就直接創建一個內部類
        //Builder也需要將所有的引數都進行暫時保存,所以Student怎么定義的這里就怎么定義
        int id;
        int age;
        int grade;
        String name;
        String college;
        String profession;
        List<String> awards;

        public StudentBuilder id(int id){    //直接呼叫建造者對應的方法,為對應的屬性賦值
            this.id = id;
            return this;   //為了支持鏈式呼叫,這里直接回傳建造者本身,下同
        }

        public StudentBuilder age(int age){
            this.age = age;
            return this;
        }
      
      	...

        public StudentBuilder awards(String... awards){
            this.awards = Arrays.asList(awards);
            return this;
        }
        
        public Student build(){    //最后我們只需要呼叫建造者提供的build方法即可根據我們的配置回傳一個物件
            return new Student(id, age, grade, name, college, profession, awards);
        }
    }
}
//主方法
public static void main(String[] args) {
    Student student = Student.builder()   //獲取建造者
            .id(1)    //逐步配置各個引數
            .age(18)
            .grade(3)
            .name("小明")
            .awards("ICPC-ACM 區域賽 金牌", "LPL 2022春季賽 冠軍")
            .build();   //最后直接建造我們想要的物件
}

單例模式

單例模式:在計算機行程中,同一個類始終只會有一個物件來進行操作,

多例模式:在計算機行程中,對一個物體類創建一次物件就是對當個物件操作,若是創建多個物件則是分別對對應的物件操作,

單例模式的三種寫法:

  1. 餓漢式單例(不建議)

    在最開始就創建了物件(太饑渴了,一開始就需要物件)

    public class Singleton {
        private final static Singleton INSTANCE = new Singleton();   //用于參考全域唯一的單例物件,在一開始就創建好
        
        private Singleton() {}   //禁用了構造方法Singleton()來創建物件,不允許隨便new,需要物件直接找getInstance
        
        public static Singleton getInstance(){   //獲取全域唯一的單例物件
            return INSTANCE;
        }
    }
    
  2. 加鎖的懶漢式單例(不建議,沒有第三種方法好)

    懶漢:在要用的時候才創建物件,但又得防多執行緒就上了鎖

    public class Singleton {
        private static volatile Singleton INSTANCE;   //在一開始先不進行物件創建,volatile關鍵字是多執行緒的時候,這個變數更改了,別的執行緒可以立馬檢測到
    
        private Singleton() {}   //禁用了構造方法Singleton()來創建物件,不允許隨便new,需要物件直接找getInstance
    
        public static Singleton getInstance(){
        if(INSTANCE == null) {	//這層判斷是便于第一次外訪問時不用在走鎖
            synchronized (Singleton.class) {	//加鎖是為了防止多執行緒創建了多個物件
                if(INSTANCE == null) INSTANCE = new Singleton();  //由于加了鎖,所以當一個行程進來創建了物件,其他執行緒需要再判斷一次有沒有人已經創建了這個類物件,有就不創建了,內層還要進行一次檢查,雙重檢查鎖定
            }
        }
        return INSTANCE;
    }
    }
    
  3. 靜態內部類的半懶、半餓式單例(建議)

    靜態內部類該開始不會加載,需要的時候才會加載,由于這個類一加載就會創建物件,

    所以實作了懶漢的資源不濫用,餓漢的防止多執行緒

    public class Singleton {
        private Singleton() {}//禁用了構造方法Singleton()來創建物件,不允許隨便new,需要物件直接找getInstance
    
        private static class Holder {   //由靜態內部類持有單例物件,但是根據類加載特性,我們僅使用Singleton類時,不會對靜態內部類進行初始化,一旦類初始化之后值將不會改變,有點餓漢式的味道,
            private final static Singleton INSTANCE = new Singleton();
        }
    
        public static Singleton getInstance(){   //只有真正使用內部類時,才會進行類初始化
            return Holder.INSTANCE;   //直接獲取內部類中的
        }
    }
    

原型模式

定義:用原型實體指定創建物件的種類,并且通過拷貝這些原型創建新的物件,(說白了就是復制)

  • 淺拷貝:①對于類中基本資料型別,會直接復制值給拷貝物件;②對于參考型別(物件型別),只會復制物件的地址,而實際上指向的還是原來的那個物件,拷貝個基莫,
public static void main(String[] args) {
    int a = 10;
    int b = a;  //基本型別淺拷貝
    System.out.println(a == b);	//true

    Object o = new Object();
    Object k = o;    //參考型別淺拷貝,拷貝的僅僅是對上面物件的參考
    System.out.println(o == k);	//true
}
  • 深拷貝:無論是基本型別還是參考型別,深拷貝會將參考型別的所有內容,全部拷貝為一個新的物件,包括物件內部的所有成員變數,也會進行拷貝,

使用Cloneable介面提供的拷貝機制,來實作原型模式:操作完會發現Object的clone默認還是淺復制

protected class Student implements Cloneable{   //注意需要實作Cloneable介面
    ...
    //Cloneable中的方法,下面代碼復制Object的clone原始碼    
    @Override
    public Object clone() throws CloneNotSupportedException {   //提升clone方法的訪問權限
        return super.clone();
    }
}

//主方法
public static void main(String[] args) throws CloneNotSupportedException {
    Student student0 = new Student();
    Student student1 = (Student) student0.clone();
    System.out.println(student0);
    System.out.println(student1);
    //兩個結果不同,就是地址不同
    
    Student student0 = new Student("小明");
    Student student1 = (Student) student0.clone();
    System.out.println(student0.getName() == student1.getName());
    //true 
}

深拷貝:在student實作介面Cloneable后重寫clone方法

@Override
public Object clone() throws CloneNotSupportedException {   //這里我們改進一下,針對成員變數也進行拷貝
    Student student = (Student) super.clone();
    student.name = new String(name);
    return student;   //成員拷貝完成后,再回傳
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/502042.html

標籤:其他

上一篇:設計模式——結構性設計模式

下一篇:設計模式之享元模式

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more