設(shè)計模式六大原則
- 單一職責(zé)原則:就一個類而言注盈,應(yīng)該僅有一個引起它變化的原因
- 開放封閉原則:類、模塊叙赚、函數(shù)等應(yīng)該是可以拓展的老客,在拓展時盡量少修改
- 里氏替換原則:所有引用基類的地方必須能透明地使用其子類對象
- 依賴倒置原則:高層模塊不應(yīng)該依賴底層模塊僚饭,兩者都應(yīng)該依賴于抽象,抽象不應(yīng)該依賴于細(xì)節(jié)胧砰,細(xì)節(jié)應(yīng)該依賴于抽象
- 迪米特原則:一個軟件實(shí)體應(yīng)當(dāng)盡可能少地與其他實(shí)體發(fā)生相互左右
- 接口隔離原則:一個類對另一個類的依賴應(yīng)該建立在最小的接口上
設(shè)計模式分類
- 創(chuàng)建型:單例浪慌、工廠方法、抽象工廠朴则、建造者权纤、原型
- 結(jié)構(gòu)設(shè)計型模式:適配器模式、裝飾模式乌妒、代理模式汹想、外觀模式、橋接模式撤蚊、組合模式古掏、享元模式
- 行為型設(shè)計模式:策略模式、模板方法模式侦啸、觀察者模式槽唾、迭代器模式、責(zé)任鏈模式光涂、命令模式庞萍、備忘錄模式、狀態(tài)模式忘闻、訪問者模式钝计、中介者模式、解釋器模式
創(chuàng)建型設(shè)計模式
單例模式
-
定義:保證一個類有且只有一個實(shí)例齐佳,并提供一個訪問的全局訪問點(diǎn)
單例模式的通用結(jié)構(gòu)圖
單例模式的6種寫法
- 餓漢模式
/**
* 單例模式
* 餓漢模式
*/
class SingletonHungry{
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry(){}
public static SingletonHungry getInstance(){
return instance;
}
}
這種方式在類加載時就完成了初始化私恬,所以類加載比較慢。但是這種方式基于類加載機(jī)制炼吴,避免了多線程同步問題本鸣。在類加載的時候就完成實(shí)例化,沒有達(dá)到懶加載的效果硅蹦。會造成內(nèi)存的浪費(fèi)
- 懶漢模式(線程不安全)
class SingletonLazyNoSafe(){
private static SingletonLazyNoSafe instance;
private SingletonLazyNoSafe() {
}
public static SingletonLazyNoSafe getInstance() {
if (instance == null) {
instance = new SingletonLazyNoSafe();
}
return instance;
}
}
懶漢式聲明了一個靜態(tài)對象荣德,在用戶第一次調(diào)用時初始化,節(jié)約了資源提针,但第一次加載時需要實(shí)例化命爬。而且在存在線程安全問題
- 懶漢模式(線程安全|雙重檢查模式DCL)
class SingletonLazySafe {
private static SingletonLazySafe instance = null;
private SingletonLazySafe(){}
public static SingletonLazySafe getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new SingletonLazySafe();
}
}
}
return instance;
}
}
這種寫法在getInstance種對Singleton實(shí)例進(jìn)行了兩次判空:第一次是為了不必要的同步第二次是在Singleton等于null的時候才創(chuàng)建實(shí)例。這里使用volatile會或多或少地影響性能辐脖。DCL的優(yōu)點(diǎn)是資源利用率高,效率高皆愉。缺點(diǎn)是第一次加載時反應(yīng)慢嗜价,DCL在某些情況下會出現(xiàn)失效的問題艇抠,也就是DCL失效。
- 靜態(tài)內(nèi)部類單例模式
class SingletonInner {
private static SingletonInner instance = null;
private SingletonInner() {
}
public static SingletonInner getInstance() {
return SingletonInner.Holder.holderInstance;
}
private static class Holder {
public static SingletonInner holderInstance = new SingletonInner();
}
}
第一次加載Singleton類時并不會初始化holderInstance,只有第一次調(diào)用getInstance方法時虛擬機(jī)加載SingletonHolder并初始化holderInstance久锥,因此比較推薦使用靜態(tài)內(nèi)部類的單例模式
- 枚舉單例
enum SingletonEnum {
INSTANCE;
public void someMethod() {
}
}
單例模式的使用場景
- 整個項(xiàng)目需要一個共享訪問點(diǎn)或共享數(shù)據(jù)
- 創(chuàng)建一個對象需要耗費(fèi)的資源過多家淤,比如IO等
- 工具類
簡單工廠模式
簡單工廠模式(靜態(tài)工廠方法模式)
-
定義:由一個工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例
結(jié)構(gòu)圖
簡單工廠模式種有如下角色:
- Factory:工廠類,簡單工廠模式的核心瑟由,它負(fù)責(zé)實(shí)現(xiàn)所有實(shí)例的內(nèi)部邏輯絮重。工廠類創(chuàng)建的產(chǎn)品類的方法可以被外界直接調(diào)用,創(chuàng)建所需的產(chǎn)品對象
- IProduct:抽象的產(chǎn)品類歹苦,簡單工廠模式所創(chuàng)建的所有對象的父類青伤,負(fù)責(zé)描述所有實(shí)例所有共有的公共接口
- Product:具體產(chǎn)品類
簡單工廠模式的實(shí)現(xiàn)
假設(shè)有一個計算機(jī)的代工生產(chǎn)商,它目前已經(jīng)可以代工生產(chǎn)聯(lián)想計算機(jī)了殴瘦。隨著業(yè)務(wù)的拓展狠角,這個代工生產(chǎn)商還要生產(chǎn)惠普和華碩的計算機(jī)。 這樣我們就需要用一個單獨(dú)的類來專門生產(chǎn)計算機(jī)蚪腋,這就用到了簡單工廠模式丰歌。
/**
* 簡單工廠模式
*/
public class SimpleFactoryType {
public static void main(String[] args) {
ComputerFactory.createComputer("hp").start();
}
}
/**
* 抽象產(chǎn)品類
*/
abstract class Computer {
/**
* 產(chǎn)品抽象方法,啟動計算機(jī)
*/
abstract void start();
}
/**
* 具體產(chǎn)品類
*/
class LenvooComputer extends Computer {
@Override
void start() {
System.out.println("lenovo start");
}
}
class HPComputer extends Computer {
@Override
void start() {
System.out.println("HP start");
}
}
class ASUSComputer extends Computer {
@Override
void start() {
System.out.println("ASUS start");
}
}
class ComputerFactory {
public static Computer createComputer(String type) {
Computer mComputer = null;
switch (type) {
case "lenovo":
mComputer = new LenvooComputer();
break;
case "hp":
mComputer = new HPComputer();
break;
case "asus":
mComputer = new ASUSComputer();
break;
}
return mComputer;
}
}
簡單工廠模式的使用場景
- 工廠類負(fù)責(zé)創(chuàng)建的對象比較少
- 客戶只需要知道傳入工廠類的參數(shù)屉凯,無須關(guān)心創(chuàng)建邏輯
優(yōu)點(diǎn)
用戶可以根據(jù)參數(shù)獲得對應(yīng)的類實(shí)例立帖。避免直接實(shí)例化類,降低了耦合性
缺點(diǎn)
可實(shí)例化的類型在編譯期間就已經(jīng)被確定悠砚。如果增加新類型厘惦,則需要修改工廠,違背了開放封閉原則哩簿。簡單工廠需要知道所有的要生產(chǎn)的類型
工廠方法模式
-
定義 定義一個用于創(chuàng)建對象的接口宵蕉,讓子類決定實(shí)例化哪個類。工廠方法使一個類的實(shí)例化延遲到其子類
image.png
在工廠方法模式種有如下角色:
- Product:抽象產(chǎn)品類
- ConcreteProduct:具體產(chǎn)品類
- Factory:抽象工廠類节榜,返回抽象產(chǎn)品對象
- ConcreteFactory:具體工廠類羡玛,返回具體產(chǎn)品實(shí)例
/**
* 工廠方法模式
*/
public class FactoryMethodType {
public static void main(String[] args) {
GDComputerFactor computerFactor = new GDComputerFactor();
computerFactor.createComputerABS(HPComputerABS.class).start();
}
}
/**
* 抽象產(chǎn)品類
*/
abstract class ComputerABS {
/**
* 產(chǎn)品抽象方法,啟動計算機(jī)
*/
abstract void start();
}
/**
* 具體產(chǎn)品類
*/
class LenvooComputerABS extends ComputerABS {
@Override
void start() {
System.out.println("lenovo start");
}
}
class HPComputerABS extends ComputerABS {
@Override
void start() {
System.out.println("HP start");
}
}
class ASUSComputerABS extends ComputerABS {
@Override
void start() {
System.out.println("ASUS start");
}
}
/**
* 抽象工廠宗苍,返回抽象的產(chǎn)品
*/
abstract class ComputerFactoryABS{
public abstract <T extends ComputerABS> T createComputerABS(Class<T> cls);
}
class GDComputerFactor extends ComputerFactoryABS {
@Override
public <T extends ComputerABS> T createComputerABS(Class<T> cls) {
ComputerABS computerABS = null;
String clsName = cls.getName();
try {
computerABS = ((ComputerABS) Class.forName(clsName).newInstance());
} catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
e.printStackTrace();
}
return (T) computerABS;
}
}
建造者模式
建造者模式也被稱為生成器模式稼稿,它是創(chuàng)建一個復(fù)雜對象的創(chuàng)建型模式,其將構(gòu)建復(fù)雜對象的過程和它的部件解耦讳窟。使得構(gòu)建過程和部件表示分離開來让歼。例如我們要 DIY 一臺臺式計
算機(jī)。 我們找到 DIY 商家丽啡。這時我們可以要求這臺計算機(jī)的 CPU谋右、 主板或者其他部件都是什么牌子的、 什么配置的补箍,這些部件是我們可以根據(jù)自己的需求來變化的改执。 但是這些部件組裝成計算機(jī)的過程是一樣的啸蜜,我們無須知道這些部件是怎樣組裝成計算機(jī)的,我們只需要提供相關(guān)部件的牌子和配置就可以了辈挂。對于這種情況我們就可以采用建造者模式衬横,將部件和組裝過程分離,使得構(gòu)建過程和部件都可以自由拓展终蒂,兩者之間的耦合也降到最低蜂林。
-
定義:將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示
結(jié)構(gòu)圖
在建造者模式種有如下角色:
- Director:導(dǎo)演類
- Builder:抽象Builder類拇泣,規(guī)范產(chǎn)品的組建噪叙,一般由子類實(shí)現(xiàn)
- ConcreteBuilder:具體建造者,實(shí)現(xiàn)Builder類定義的所有方法挫酿,返回組建好的對象
- Product:產(chǎn)品類
建造者模式的簡單實(shí)現(xiàn)
public class BuilderTypeLSN {
public static void main(String[] args) {
ApplePhoneBuilder phoneBuilder = new ApplePhoneBuilder();
Director director = new Director(phoneBuilder);
Phone phone = director.createPhone("aaa", "b", "c");
}
}
class Phone {
private String mCPU;
private String mMainboard;
private String mRam;
public void setmCPU(String mCPU) {
this.mCPU = mCPU;
}
public void setmMainboard(String mMainboard) {
this.mMainboard = mMainboard;
}
public void setmRam(String mRam) {
this.mRam = mRam;
}
}
abstract class Builder{
abstract void buildCPU(String cpuName);
abstract void buildMainboard(String boardName);
abstract void buildRam(String ram);
abstract Phone createPhone();
}
class ApplePhoneBuilder extends Builder {
Phone phone = new Phone();
@Override
void buildCPU(String cpuName) {
phone.setmCPU(cpuName);
}
@Override
void buildMainboard(String boardName) {
phone.setmMainboard(boardName);
}
@Override
void buildRam(String ram) {
phone.setmRam(ram);
}
@Override
Phone createPhone() {
return phone;
}
}
class Director {
Builder mBuilder = null;
public Director(Builder mBuilder) {
this.mBuilder = mBuilder;
}
public Phone createPhone(String cpu, String board, String ram) {
mBuilder.buildCPU(cpu);
mBuilder.buildMainboard(board);
mBuilder.buildRam(ram);
return mBuilder.createPhone();
}
}
使用建造者的場景和優(yōu)缺點(diǎn)
- 使用場景
- 當(dāng)創(chuàng)建復(fù)雜對象的算法應(yīng)該獨(dú)立于該對象的組成部分以及它們的裝配方式時构眯。
- 相同的方法,不同的執(zhí)行順序早龟,產(chǎn)生不同的事件結(jié)果時惫霸。
- 多個部件或零件都可以被裝配到一個對象中,但是產(chǎn)生的運(yùn)行結(jié)果又不相同時葱弟。
- 產(chǎn)品類非常復(fù)雜壹店,或者產(chǎn)品類中的調(diào)用順序不同而產(chǎn)生了不同的效能。
- 在創(chuàng)建一些復(fù)雜的對象時芝加,這些對象的內(nèi)部組成構(gòu)件間的建造順序是穩(wěn)定的硅卢,但是對象的內(nèi)部組成構(gòu)件面臨著復(fù)雜的變化。
- 優(yōu)點(diǎn):
- 使用建造者模式可以使客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)藏杖。
- 具體的建造者類之間是相互獨(dú)立的将塑,容易擴(kuò)展。
- 由于具體的建造者是獨(dú)立的蝌麸,因此可以對建造過程逐步細(xì)化点寥,而不對其他的模塊產(chǎn)生任何影響。
- 缺點(diǎn): 產(chǎn)生多余的 Build 對象以及導(dǎo)演類