25年上半年五月之軟考之設計模式

目錄

一、單例模式

二、工廠模式

三、?抽象工廠模式

四、適配器模式

五、策略模式

六、裝飾器模式

?編輯

考點:會挖空super(coffeOpertion);

七、代理模式

為什么必須要使用代理對象?

和裝飾器模式的區別

八、備忘錄模式


一、單例模式

這個模式能確保一個類只有一個實例,并提供全局訪問點,非常適合配置管理、日志對象等場景。

我們不使用單例模式的時候會導致

  1. 內存浪費(重復加載配置)

  2. 配置不一致(不同實例可能讀取不同狀態)

以下是不使用單例模式的例子

public class Printer {// 構造函數,用于初始化打印機對象時打印提示信息public Printer() {System.out.println("這是一臺普通的打印機");}public static void main(String[] args) {// 創建第一個打印機對象Printer printer1 = new Printer();// 創建第二個打印機對象Printer printer2 = new Printer();// 判斷兩個打印機對象是否為同一實例,并輸出結果System.out.println("printer1和printer2是同一臺嗎?" + (printer1 == printer2));}
}

運行結果

這是使用單例模式的結果:

知識點掃盲:
// ? ?互斥訪問 使用關鍵字synchronized 意思是打印完第一個,才能打印第二個,保證有序

public class Printer1 {private static Printer1 instance;
private Printer1(){System.out.println("全公司唯一一臺打印機已經啟動");
}
private static synchronized Printer1 getInstance(){if (instance==null){instance = new Printer1();}return instance;
}public void PrintDocument(String employee,String document){System.out.println(employee+"正在打印"+document);
}
public static void main(String[] args) {
//    員工A申請使用打印機Printer1 printerA = Printer1.getInstance();
//    員工B申請使用打印機Printer1 printerB= Printer1.getInstance();
//    檢查是否是同一臺打印機System.out.println("printerA和printerB是同一臺嗎?"+(printerA==printerB));}
}

true

二、工廠模式

假設你開了一家奶茶店,顧客可以點不同口味的奶茶(原味、芒果、草莓)。
問題:如果直接在代碼里用new創建每種奶茶,會導致:

  1. 代碼臃腫(每次新增口味都要改多處邏輯)

  2. 難以維護(制作流程分散在各處)

解決方案:用工廠模式統一管理奶茶的創建過程!

首先我們先掃盲一下接下來代碼的知識點

package org.factory;
public class Case {public static void main(String[] args) {String str1="Hello";String str2="hello";String str3="World";boolean result1 =str1.equals(str2);boolean result2 =str1.equalsIgnoreCase(str2);System.out.println(result1);  // 輸出falseSystem.out.println(result2);  // 輸出true}}

equalsIgnoreCase()?是?Java 中?String?類的一個方法,用于比較兩個字符串的內容是否相同,忽略大小寫差異

首先,先來梳理一下代碼思路。首先定義一個接口,將制作奶茶的步驟在這個接口里。

之后創建不同的類實現先創建的接口,表示某種奶茶的具體制作過程。

之后創建工廠類,在工廠類里,客人要點什么奶茶就做什么奶茶。

最后,客人點單,具體喝什么奶茶就使用什么方法的調用。也算是做到了一個客戶與程序之間的交互。

可能有人會疑問,為什么要寫接口,為什么要寫不同的奶茶類,試想,如果我們把所有實現奶茶的方法放在一個類里,讓客戶去從一個類里調用,判斷條件會變多,代碼也會變得很長,我們在尋找這些條件的時候,運行速度可能會變慢。所以當我們想要添加新口味時,前者需要修改同一個類,而后者只需擴展,不會影響已有代碼。

這里也運用了多態的思想,客戶點奶茶時,無論奶茶是原味、芒果還是其他類型,客戶端都通過同一個接口方法(如prepare())操作。本質就是,不同奶茶類(Original、Mango)對這些方法有不同的實現。

經常面試題里會出現多態這樣的提問,我以前會說,就像水,可以是冰,可以是氣。現在我明白了,就像奶茶有不同的口味,就像王者榮耀的英雄同樣是攻擊卻有不同的傷害技能,可以是物理攻擊可以是法術攻擊。

接下來我們來具體實現,觀察工廠模式的作用。

至少需要5個文件來實現。

1.定義同一種類的行為模式

package org.factory;public interface MilkTea {void prepare();//準備材料void make();//制作奶茶void pack();//打包
//這里介紹了奶茶的制作過程
}

2.具體類里是做什么

我們實現接口,注意:接口是實現,類是繼承

這是經典珍珠奶茶

package org.factory;public class OriginalMilkTea implements MilkTea{
//    代碼實現流程:/*** 1.創建接口* 2.實現接口* 3.創建工廠類,在工廠中實現制造奶茶* 4.賣給客戶不同的奶茶* 我們可以創建很多類似的類去表示不同奶茶的制作方式*/@Overridepublic void prepare() {
//    如果我要做珍珠奶茶 珍珠、紅茶、牛奶System.out.println("正在準備材料");System.out.println("準備好材料:珍珠、紅茶、牛奶");}@Overridepublic void make() {System.out.println("正在制作中");}@Overridepublic void pack() {System.out.println("用經典杯打包原味奶茶!");}
}

這是紅糖姜茶

package org.factory;public class RedSugarTea implements MilkTea{/*此類我表示的是紅糖姜茶*/@Overridepublic void prepare() {System.out.println("準備材料!");System.out.println("紅糖、生姜、紅茶");}@Overridepublic void make() {System.out.println("混合熬煮中!");}@Overridepublic void pack() {System.out.println("使用夏季限定包裝杯包裝!");}/**/
}

3.工廠模式來進行判斷生產

package org.factory;public class MilkFactory {
//    工廠里面制作奶茶
//    客人需要什么奶茶我就制作什么奶茶,所以需要我們定義一個函數public static MilkTea createTea (String type){if ("Orginal".equalsIgnoreCase(type)){return new OriginalMilkTea();}else if ("RedSugar".equalsIgnoreCase(type)){return new RedSugarTea();}throw new IllegalArgumentException("沒有這種口味的奶茶");}
}

4.客戶需要去定義 這里也相當于一個測試類? 假如需要喝紅糖姜茶

package org.factory;public class Customer {public static void main(String[] args) {MilkTea RedSugar =MilkFactory.createTea("RedSugar");RedSugar.prepare();RedSugar.make();RedSugar.pack();}
}

接口就是一個數據類型,后面是一個對象,用對象去調用接口里面的方法,再識別出需要去調用哪個方法。

三、?抽象工廠模式

生活實例:蘋果 vs 小米全家桶

假設你要購買一套電子產品,包含?手機?和?耳機。不同品牌(如蘋果、小米)的產品風格不同,且手機和耳機需要配套使用(比如蘋果手機和AirPods配對更佳)。
抽象工廠模式?就是用來生產?同一品牌系列產品?的解決方案,確保你獲得的手機和耳機是同一品牌風格,避免混搭不兼容。

上一個我們講的是制作奶茶的過程,但是只是同一款產品,那就是奶茶。

但是在此設計模式中,可以同時制造耳機和手機,只需要多設計一些接口和實現類。生產?多個相關聯的產品(比如同時生產手機+耳機+手表,且保證同一品牌)。

四、適配器模式

顧名思義,適配器模式主要用于解決接口不兼容的問題,讓原本無法一起工作的類可以協同工作。生活中常見的例子是電源適配器,比如不同國家的插頭標準不同,適配器可以讓不同插頭在同一個插座上使用。

其實我覺得這個雖然好理解,但是我感覺代碼是不好理解的。

本質是功能不同的兩個類,轉為功能相同的一個類。

實際例子:現在有英語導游給中國人導游 為了讓中國人聽得懂外語 ,? ?發明了耳機適配器.

代碼實現:先明確輸出的是中文,英文是英語導游說的,適配器是將英語導游的話轉換為中文。

1.定義一個接口

package org.adapter;public interface ChineseSpeaker {
//    我們是將英文翻譯成中文 這里定義的是說中文的能力String ChineseAbility();
}

2.英語導游說英語

package org.adapter;public class EnglishGuide {public String SpeakEnglish(){return "Hello !This is a GreatWall";}
}

3.,首先讓值傳入翻譯器中,翻譯之后,傳出來

package org.adapter;public class Translator implements ChineseSpeaker{private EnglishGuide guide;public Translator(EnglishGuide guide){this.guide=guide;}
//   翻譯功能,要先傳入英文,再讓其轉換為中文@Overridepublic String ChineseAbility() {String message = guide.SpeakEnglish();
// replace原來的值    想要替換的值return message.replace("Hello !This is a","你好!這里是");
//        System.out.println(replace(message,"Hi,這里是"));}
}

4.給翻譯器傳入值,調用接口實現的函數

package org.adapter;public class Test {public static void main(String[] args) {EnglishGuide englishGuide = new EnglishGuide();Translator translator = new Translator(englishGuide);System.out.println(translator.ChineseAbility());}
}

五、策略模式

這個模式很好理解,面對同一個類有不同的策略,假如你想買車,不考慮預算,你想買什么車就買什么車,可以買白色寶馬,灰色寶馬,黑色寶馬,黑色奔馳,灰色奔馳,白色小米,黃色小米,等等。任意搭配。我們把所有能夠組成的策略的類都生成出來。代碼文件很多。

需要定義的東西很多,我們需要把不同屬性作為接口抽出來,比如顏色,品牌,油型。

假如我們想要買白色特斯拉用98的油型。就是這樣的代碼。

package org.strategy;public abstract class Car {
//    Car  顏色、油、品牌protected Color color;protected Soil soil;protected Brand brand;protected void info() {String info = color.color() + brand.Brand() + ": " + soil.soil();System.out.println(info);}}
package org.strategy;public class tebaiba extends Car{public tebaiba() {color = new WhiteImp();brand = new Tesila();soil = new Ninety_eight();}
}
package org.strategy;public class Test {public static void main(String[] args) {Car tebaiba = new tebaiba();tebaiba.info();}
}


White特斯拉: 98

在考試的時候最有可能挖空就是挖?

第一個空一般都是接口或者抽象類。

六、裝飾器模式

我使用了DeepSeek預測,今年最可能考的就是裝飾器模式和代理模式。

不修改原有對象,只是將原有對象進行加工。

這里我們使用(咖啡加料系統)來進行學習。

假如普通咖啡10元,不加糖。假如我們這里有兩種操作。

A類咖啡:我們需要加椰果來增加口感,價格就變成了12元。

B類咖啡:我們需要加牛奶來增加醇香,價格就變成了15元。

1.? ? ? ?接口類

package org.Decorator;public interface CoffeOpertion {
//    1.對咖啡進行加料String addSugar();
//    2.對咖啡進行加價double price(double money);
}

2.? ? ? ?實現普通咖啡類

package org.Decorator;public class SimpleCoffe implements CoffeOpertion{
//    我們首先要知道普通咖啡是什么規格,再進行裝飾@Overridepublic String addSugar() {return "無糖";}@Overridepublic double price(double money) {return 10.0;}
}

3.? ? ? ?抽象裝飾類

package org.Decorator;
//抽象裝飾類
public abstract class CoffeeDecorator implements CoffeOpertion {protected CoffeOpertion coffeOpertion;
//    這個是裝飾類,你要把裝飾的對象傳進來public CoffeeDecorator(CoffeOpertion coffeOpertion){this.coffeOpertion=coffeOpertion;}}

4.? ? ? ?A操作

package org.Decorator;public class CoffeDecoratorA extends CoffeeDecorator{public CoffeDecoratorA(CoffeOpertion coffeOpertion) {super(coffeOpertion);}@Overridepublic String addSugar() {return "A類咖啡飲品,額外加椰果";}@Overridepublic double price(double money) {money = money+2;return money;}
}

5.B操作

package org.Decorator;public class CoffeDecoratorB extends CoffeeDecorator{public CoffeDecoratorB(CoffeOpertion coffeOpertion) {super(coffeOpertion);}@Overridepublic String addSugar() {return "拿鐵咖啡,額外加牛奶";}@Overridepublic double price(double money) {money =money+5;return money;}
}

6.? ? ? ?實現類

package org.Decorator;public class Coffeshop extends SimpleCoffe{public static void main(String[] args) {SimpleCoffe simple = new SimpleCoffe();String sugar=simple.addSugar();double money = simple.price(10);System.out.println("這是普通咖啡的規格:"+sugar + ",價格" + money);CoffeOpertion coffeOpertionA= new CoffeDecoratorA(new SimpleCoffe());CoffeDecoratorB coffeDecoratorB = new CoffeDecoratorB(new SimpleCoffe());System.out.println(coffeOpertionA.addSugar()+"價格為"+coffeOpertionA.price(10));System.out.println(coffeDecoratorB.addSugar()+"價格為"+coffeDecoratorB.price(10));}
}

這是運行結果

考點:會挖空super(coffeOpertion);

在子類的構造函數里一定要強調父類。

    public CoffeDecoratorA(CoffeOpertion coffeOpertion) {super(coffeOpertion);
//        this.coffeOpertion=coffeOpertion;}

七、代理模式

為什么必須要使用代理對象?

1.隱藏復雜性 :代理對象可以控制何時、如何創建真實對象(例如延遲加載)

2.功能擴展:代理可以在不修改真實對象的前提下,添加額外邏輯(緩存、權限驗證)

3.接口透明:客戶端無需知道背后是代理還是真實對象,只需調用統一接口

和裝飾器模式的區別

  • 代理:控制訪問,側重隱藏真實對象(如權限控制)。

  • 裝飾器:動態擴展功能,側重增強(如咖啡加糖)。

代碼實現:一個真實的類,一個代理真實的類,一個抽象的接口,代理與真實的類擁有相同的功能。在特定條件下被實現,比如,老師今天感冒不能上課就由課代表代表上課。

2

1.

package org.Proxy;public interface Lesson {String CanLesson();
}

2.

package org.Proxy;public class RealTeacher implements Lesson{@Overridepublic String CanLesson() {return "老師正在朗讀荷塘月色";}
}

3.

package org.Proxy;public class StudentProxy implements Lesson{
//    關鍵:持有真實對象的引用protected RealTeacher teacher;
//    構造函數public StudentProxy(){this.teacher = new RealTeacher();}
//    添加檢查權限,沒有老師的時候學生上課public boolean checkPermission(){return false;}@Overridepublic String CanLesson() {// 添加代理邏輯(示例:權限校驗)if (checkPermission()) {return "老師在,老師上課:\n" +teacher.CanLesson();} else {return "老師不在學生代替老師上課,語文課代表正在朗讀荷塘月色\n";}}
}

4.

package org.Proxy;public class Test {public static void main(String[] args) {StudentProxy proxy = new StudentProxy();String message= proxy.CanLesson();System.out.println(message);}
}

對我來說寫多了,好像調用來調用去沒什么區別哈哈。。。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/84463.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/84463.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/84463.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python打卡第36天

浙大疏錦行 作業: 對之前的信貸項目,利用神經網絡訓練下,嘗試用到目前的知識點讓代碼更加規范和美觀。 import torch import torch.nn as nn import torch.optim as optim from sklearn.model_selection import train_test_split from sklear…

全面理解類和對象(下)

文章目錄 再談構造函數初始化列表 static概念: 友元友元函數友元類 內部類再次理解類和對象 再談構造函數 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;} private:int _year;int _month;int _day; };上述代碼有了…

TomatoSCI分析日記——層次聚類

TomatoSCI分析日記——層次聚類 今天介紹的是一種常見的聚類方法——層次聚類。層次聚類會將數據集劃分成嵌套的簇,形成一個層次結構(樹狀圖),經常用于探究樣本的相似性。用大白話來說,就是:我有一大堆樣品…

mysql都有哪些鎖?

MySQL中的鎖機制是確保數據庫并發操作正確性和一致性的重要組成部分,根據鎖的粒度、用途和特性,可以分為多種類型。以下是MySQL中常見的鎖及其詳細說明: 一、按鎖的粒度劃分 行級鎖(Row-level Locks) 描述:…

flutter 項目調試、flutter run --debug調試模式 devtools界面說明

Flutter DevTools 網頁界面說明 1. 頂部導航欄 Inspector:查看和調試 Widget 樹,實時定位 UI 問題。Performance-- 性能分析面板,查看幀率、CPU 和 GPU 使用情況,識別卡頓和性能瓶頸。Memory-- 內存使用和對象分配分析&#xff…

使用Kotlin創建Spring Boot用戶應用項目

項目初始化與配置 通過Spring Initializr創建Kotlin項目 若需使用Kotlin語言開發Spring Boot應用(假設已安裝Kotlin環境),可通過start.spring.io進行項目初始化。在項目創建頁面需進行以下關鍵配置: 語言選擇:切換至Kotlin選項項目元數據:需填寫Group(如com.apress.us…

【Linux網絡篇】:Socket網絡套接字以及簡單的UDP網絡程序編寫

?感謝您閱讀本篇文章,文章內容是個人學習筆記的整理,如果哪里有誤的話還請您指正噢? ? 個人主頁:余輝zmh–CSDN博客 ? 文章所屬專欄:Linux篇–CSDN博客 文章目錄 網絡編程套接字一.預備知識1.理解源IP地址和目的IP地址2.認識端…

Python爬蟲實戰:研究Newspaper框架相關技術

1. 引言 1.1 研究背景與意義 互聯網的快速發展使得新聞信息呈現爆炸式增長,如何高效地獲取和分析這些新聞數據成為研究熱點。新聞爬蟲作為一種自動獲取網頁內容的技術工具,能夠幫助用戶從海量的互聯網信息中提取有價值的新聞內容。本文基于 Python 的 …

【node.js】實戰項目

個人主頁:Guiat 歸屬專欄:node.js 文章目錄 1. 項目概覽與架構設計1.1 實戰項目:企業級電商管理系統1.2 技術棧選擇 2. 項目初始化與基礎架構2.1 項目結構設計2.2 基礎配置管理 3. 用戶服務實現3.1 用戶服務架構3.2 用戶模型設計3.3 用戶服務…

Mybatis框架的構建(IDEA)

選擇maven項目 修改設置 在設置中添加自定義代碼模板 開始寫代碼 動態SQL語句的示例&#xff1a; pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"…

經濟法-6-公司法律制度知識點

一、出資期限 1.有限責任公司&#xff1a;全體股東需在公司成立之日起5年內繳足認繳的注冊資本 2.股份有限公司&#xff1a;以發起方式設立的&#xff0c;發起人需在公司登記前實繳全部股款 3.認繳期加速到期 公司不能清償到期債務的&#xff0c;公司或者已到期債權的債權人…

jquery.table2excel方法導出

jquery提供了一個table2excel方法可以用來導出頁面到xls等 $("#grid_595607").table2excel({exclude: ".noExport", // 排除類名為 noExport 的元素filename: "導出數據.xls",exclude_img: true, // 不導出圖片exclude_links: true, // 不導…

echarts設置標線和最大值最小值

echarts設置標線和最大值最小值 基本ECharts圖表初始化配置 設置動態的y軸范圍&#xff08;min/max值&#xff09; 通過markPoint標記最大值和最小值點 使用markLine添加水平參考線 配置雙y軸圖表 自定義標記點和線的樣式&#xff08;顏色、符號等&#xff09; 響應式調整圖表大…

Java文件操作:從“Hello World”到“Hello File”

&#x1f50d; 開發者資源導航 &#x1f50d;&#x1f3f7;? 博客主頁&#xff1a; 個人主頁&#x1f4da; 專欄訂閱&#xff1a; JavaEE全棧專欄 文件 什么是文件&#xff1f; 廣義&#xff1a;操作系統進行資源管理的一種機制&#xff0c;很多的軟件/硬件資源&#xff0c;…

2025第三屆黃河流域網絡安全技能挑戰賽--Crypto--WriteUp

2025第三屆黃河流域網絡安全技能挑戰賽–Crypto–WriteUp Crypto sandwitch task from Crypto.Util.number import * import gmpy2 flag bflag{fake_flag} assert len(flag) 39 p getPrime(512) q getPrime(512) n p * q e 0x3 pad1 beasy_problem pad2 bHow_to_so…

三重天理論

第一重天&#xff1a;公理層&#xff08;形而上地基&#xff09; 這里構建的是人類理性的"操作系統"&#xff0c;公理作為不證自明的邏輯起點&#xff08;如矛盾律/同一律&#xff09;&#xff0c;恰似海德格爾所說的"存在之鏡"。黑格爾辯證法在此顯現為動…

2025年第八屆廣西大學生程序設計大賽(正式賽)題解(更新中)

知乎評價&#xff1a;如何評價2025年第八屆GXCPC廣西大學生程序設計大賽暨中國-東盟國際大學生程序設計大賽&#xff1f; 榜單&#xff1a;牛客比賽排名 題目鏈接&#xff1a;第八屆廣西大學生程序設計大賽暨2025邀請賽 TIP&#xff1a;提交處可查看別人過題代碼 難度簽到題普通…

WHAT - 兆比特每秒 vs 兆字節每秒

文章目錄 Mbps 解釋Mbps 和 MB/s&#xff08;兆字節每秒&#xff09;換算總結網絡場景1. 在路由器設置中的 Mbps2. 在游戲下載時的 Mbps / MB/s總結 Mbps 解釋 首先&#xff0c;Mbps 是一個常見的網絡帶寬單位&#xff0c;意思是&#xff1a; Megabits per second&#xff08;…

[C語言實戰]C語言內存管理實戰:實現自定義malloc與free(四)

[C語言實戰]C語言內存管理實戰&#xff1a;實現自定義malloc與free&#xff08;四&#xff09; 摘要&#xff1a;通過實現簡化版的內存管理器&#xff0c;深入理解動態內存分配的核心原理。本文包含內存塊設計、分配算法、空閑合并策略的完整實現&#xff0c;并附可運行的代碼…

YOLOv8源碼修改(5)- YOLO知識蒸餾(下)設置蒸餾超參數:以yolov8-pose為例

目錄 前言 1. 不同蒸餾算法資源占用 2. 不動態調整蒸餾損失 2.1 訓練定量化結果 2.1 訓練結果可視化結果 3. 動態調整蒸餾損失權重及實驗分析 3.1 余弦衰減和指數衰減 3.2 CWD蒸餾損失 3.3 MGD蒸餾損失 3.4 AT蒸餾損失 3.5 SKD和PKD蒸餾損失 4. 調權重心得總結 5…