成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一文分清Java開發中容易混淆的四大設計模式

原創
開發 前端
為什么先說工廠模式呢?因為“工廠”這個概念在我們代碼中到處都體現著,很多設計模式也離不開它,以它作為基礎演進,所以先要學習它。什么是“工廠”?就像我們生活中的工廠是一樣的,就是生產某些“物品”的地方。

作者 | 蔡柱梁

可能很多人認為設計模式只有面試時用到,這也不能算錯吧。但是如果僅僅只是面試時背背八股文,在實際工作中遇到了應該使用,卻不知道要用,那么你的代碼能有多好也是自欺欺人的了。那么什么時候應該使用設計模式呢?

換個角度說吧,大家覺得設計模式是怎么出來的?其實就是大牛們寫代碼多了,覺得一些高度重復或相似的地方,可以做到更好的“高內聚”,“低耦合”。他們不斷改進,然后對他們的這些設計思路進行總結,最后得到的就是我們現在的設計模式。本文就給大家介紹幾個常用的設計模式。

1.工廠模式

為什么先說工廠模式呢?因為“工廠”這個概念在我們代碼中到處都體現著,很多設計模式也離不開它,以它作為基礎演進,所以先要學習它。什么是“工廠”?就像我們生活中的工廠是一樣的,就是生產某些“物品”的地方。

在 Java 代碼中,我們用各式各樣的對象做各種事情,而這個過程中,我們往往是不關心創建過程的,僅僅關注它有那些方法可使用,提供了什么功能。這時,我們可以使用工廠模式進行解耦——創建的行為放在工廠里,而使用的人專注于使用工廠產生的工具。在下面的模板方法、策略模式、適配器模式中,都能看到工廠模式的身影。

我們所說的工廠模式一般有兩種:

  • 工廠方法
  • 抽象工廠

(1)工廠方法

工廠方法模式是一種創建型設計模式, 其在父類中提供一個創建對象的方法, 允許子類決定實例化對象的類型。

工廠方法的具體實現思路是:

  • 制定一個創建對象 A 的接口工廠
  • 這個工廠的實現類構建 A 的子類,如:A1、A2、A3……

通過這種方式實現對象和對象的創建的分離,可能覺得很雞肋吧?下面通過場景對比說明它的好處。

用傳統做法與使用了工廠方法的場景對比:

  • 傳統寫代碼
  • 我需要用到某個類,比如 A1,我就 new A1 出來,然后進行業務操作。有一天產品告訴我這段邏輯需要增加一個 A2 的業務操作邏輯,我就得通過條件判斷增加邏輯。可是 A1 和 A2 在業務抽象上是一致的,僅僅是實現細節不同(舉個例子:好比運輸,我用貨車運輸是運輸,我用火車運輸也是運輸,也就是說運輸是目的,我的實現方式可以多樣化)。這時,通過 if/else 或 switch 來寫就不符合開閉原則了。
  • 用了工廠方法寫代碼
  • 我代碼上一開始就寫著是運輸工具,用這個運輸工具運輸(注意這里是抽象概念運輸工具而已)。這樣,我就可以根據業務計算得到的條件(如:公路/鐵路/海運/空運)丟給工廠,工廠給我返回具體的運輸工具就行(反正子類能強轉成父類)。

使用了工廠方法后,我的業務代碼不需要關注具體的運輸工具是什么,然后再去看它怎么運輸,后續產品加再多運輸工具,transport()的這段代碼都不會被干擾,符合了開閉原則。

偽代碼如下:


public interface TransportToolFactory {
TransportTool createTool();
}

public class TruckTransportToolFactory implements TransportToolFactory {
@Override
public TransportTool createTool() {
...
}
}

public class BoatTransportToolFactory implements TransportToolFactory {
@Override
public TransportTool createTool() {
...
}
}

public class Transport {
private TransportToolFactory factory;

public Transport(int way) {
if (way == 0) {
factory = new TruckTransportToolFactory();
}
...
}

public void transport() {
TransportTool tool = factory.createTool();
// 繼續業務處理
}
}

簡單說下“簡單工廠”,偽代碼如下:

public void transport() {
int way = getWay();// 經過計算也好,前端傳過來也好,反正得到了具體的運輸方式
TransportTool tool = new TransportToolFactory(way).createTool();
// 繼續業務處理
}

public TransportTool createTool() {
if (way == 0) {
// 貨車
}
...
}

不過簡單工廠的缺點很明顯:

沒有做到單一職責,從上面的例子不難看出,汽車、輪船、飛機、大炮都包了,如果業務足夠復雜,這個工廠類真的是誰維護誰知道!

(2)抽象工廠

抽象工廠模式是一種創建型設計模式, 它能創建一系列相關的對象, 而無需指定其具體類。

在我看來,JDBC 對抽象工廠模式的應用就十分經典。DB 有很多種,但是在不同的公司選擇可能都不太一樣,有些是 MySQL,有些是 Oracle,甚至有些是 SQL Sever 等等。但是對于我們開發而言,這些都是 DB,如果它們的連接,提交事務,回滾事務等細節都需要我們注意的話(不同 DB 的具體實現處理會有差異),這顯然是很麻煩的,而且我們也不關心。我們要的只是使用 Connection 創建 Session,Session 開啟事務等等。

如果有一個類可以將這一系列共性的行為都提取出來(如連接,事務處理等),我們只要使用這個抽象類和它提供的方法就好了。事實上,JDBC 也的確是這么做的,我們在配置好具體的數據庫配置后,在代碼上只要用接口 Factory 創建連接、會話,開啟事務……

首先,連接是個對象,會話也是對象,事務也是,創建這些對象的方法都抽象到一個工廠里面,而這個工廠本身也只是一個接口定義,這就是所謂的抽象工廠;如果這時我使用的是MySQL,那么剛剛羅列的那些對象都是MySQL定制化的一系列相關對象,這就是所謂的“能創建一系列相關的對象”。

2.模板方法模式

模板方法模式是一種行為設計模式,它在超類中定義了一個算法的框架, 允許子類在不修改結構的情況下重寫算法的特定步驟。

模板方法的核心在于抽象上行為性質一樣,實際行為上有差別。

舉個例子:

我們產品常常要收集各式各樣的數據來分析用戶行為。有時他們為了效率會給開發一堆電子文檔(如 CSV、DOC、TXT等等,這些文檔記錄著類似的數據,但是數據結構肯定是不同的),讓開發按照他們要求開發個系統功能可以導入,按他們的要求統計這些數據。

對于開發而言,代碼是差不多的,都要導入文件,解析文件,邏輯計算后入庫。偏偏我們導入文件后,解析文件代碼不同,邏輯計算有時也會有差異,但是對于最后一步落庫卻大概率是一樣的。對于這種類型的業務場景,我們可以定個類去規定好這些流程,上游調用時就是調用我這個類的子類,子類會根據自己的業務場景重寫自己需要的流程節點的邏輯。

3.策略模式

策略模式是一種行為設計模式, 它能讓你定義一系列算法, 并將每種算法分別放入獨立的類中, 以使算法的對象能夠相互替換。

舉例子說明:

我們接入一個審批流組件,我們自己后臺也要留一份提審的記錄(方便查詢和回溯),現在我們希望我們做的這個功能通用性要強一些,也就是可以做到讓其他功能想加入這個審批流程就加入,如:功能鑒權的授權,工作流配置等等。

那么一開始審批時,一定是只有提審數據,而我們的鑒權授權或者工作流配置肯定是沒生成到對應表的,只有審批通過后才會真的授權或者生成配置。這時問題來了,當工作流組件回調我們,難道我們每加入一個就 copy 上一個功能的回調代碼,刪掉修改審批狀態后的代碼,改改就好了嗎?這里得冗余多少代碼,哪怕你修改審批流的代碼抽取成一個方法,你也會發現每個回調方法里都有你那個方法。

具體偽代碼如下:

public class CallBack {
public void callback1(Param param) {
// 查詢審批記錄的合法性

// 修改審批記錄

// 處理業務邏輯1
}
public void callback1(Param param) {
// 查詢審批記錄的合法性

// 修改審批記錄

// 處理業務邏輯2
}
......
}

這種場景我們可以使用策略模式優化,我們將處理業務邏輯當成個算法對象抽離出來,不同業務場景的回調業務處理器實現這個抽離接口,用策略自動分配對應的處理器即可。

偽代碼如下:

public class CallBack {
private Strategy strategy = new Strategy();
public void callback(Param param) {
// 查詢審批記錄的合法性

// 修改審批記錄

// 處理業務邏輯
strategy.getHandle(param.getServiceName()).invokeHandle();
}
}
public class Strategy {
private Map<String, Iservice> map;

static {
map = new HashMap<String, Iservice>();
map.put("Service1", new Service1());
map.put("Service2", new Service2());
......
}

public Iservice getHandle(String serviceName) {
return map.get(serviceName);
}
}
public class Service1 implements Iservice {
@Override
public void invokeHandle() {
...
}
}
public class Service2 implements Iservice {
@Override
public void invokeHandle() {
...
}
}
......

4.適配器模式

適配器模式是一種結構型設計模式, 它能使接口不兼容的對象能夠相互合作。

說到適配器,我想大家很快就想到了一個場景:

我們家庭的標準電壓是220V左右(實際會有點誤差),我們大家電自然需要這么高的電壓才能工作,但是我們小家電呢?如:手機充電,電腦等等。這些小家電往往都會有個“中介”——適配器去幫他們將標準電壓轉化成他們的適用電壓。

其實我們的適配模式也是一樣的。這里我們來看下 Spring 的實戰使用,上源碼:


/**
* Extended variant of the standard {@link ApplicationListener} interface,
* exposing further metadata such as the supported event and source type.
*
* <p>As of Spring Framework 4.2, this interface supersedes the Class-based
* {@link SmartApplicationListener} with full handling of generic event types.
*
* @author Stephane Nicoll
* @since 4.2
* @see SmartApplicationListener
* @see GenericApplicationListenerAdapter
*/
public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
...

在 4.2 版本之前,Spring 監聽觸發事件的監聽器使用的是 ApplicationListener,經過這么多迭代后,它想增強下該功能,所以又定義了一個 GenericApplicationListener。但是這里有個問題,以前實現 ApplicationListener 的那些子類也還是要兼容的!!!全部重寫,那很累人;不兼容,作為高熱度的開源框架,這是不能接受的。這時,Spring 的作者就采用了適配模式,具體應用代碼如下:

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// 我們都知道 spring 的廣播事件都是是用了這個接口,我們看下 spring 是怎么做兼容的
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
// 重點在這 getApplicationListeners(event, type),看看他們是怎么 get 這個 list 的
// getApplicationListeners 是父類 AbstractApplicationEventMulticaster 的方法
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
}

AbstractApplicationEventMulticaster#getApplicationListeners 里面做了大量的性能優化,不是本文的重點,所以這里跳過了。大家只要知道它第一次拿的地方是:

AbstractApplicationEventMulticaster#retrieveApplicationListeners 。

這就夠了,而這個方法里面給 list 添加元素的方法是:

AbstractApplicationEventMulticaster#supportsEvent(ApplicationListener, ResolvableType, Class),這才是我們要看的代碼。

protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
// 這里先看下這個 listener 是不是 GenericApplicationListener 的子類
// 不是就轉化成 GenericApplicationListener,這樣以前 ApplicationListener 的子類就能被兼容了
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

5.總結

希望上面的幾個設計模式的應用例子能給大家一點啟發,能在自己工作中找到共同點去嘗試應用。不過,也不要濫用設計模式,因為一些剛起步的公司,業務方向也還不穩定,很難去抽取共同的抽象部分又或者由于業務太簡單了,造成了過度設計,這些都是不可取的。

作者介紹

蔡柱梁,51CTO社區編輯,從事Java后端開發8年,做過傳統項目廣電BOSS系統,后投身互聯網電商,負責過訂單,TMS,中間件等。

責任編輯:武曉燕 來源: 51CTO技術棧
相關推薦

2020-04-07 09:21:45

MySQL數據庫SQL

2022-06-29 11:28:57

數據指標體系數據采集

2025-01-03 09:30:01

2024-02-26 11:52:38

代理模式設計

2024-02-19 13:11:38

門面模式系統

2024-01-29 12:22:07

設計模式策略模式

2023-05-22 13:27:17

2024-02-04 12:04:17

2024-02-27 11:59:12

享元模式對象

2024-02-21 12:24:33

模板設計模式框架

2024-01-30 13:15:00

設計模式責任鏈

2024-02-23 12:11:53

裝飾器模式對象

2023-11-02 13:33:00

Python數據結構

2022-09-21 16:56:16

設計模式微服務架構

2024-12-31 10:36:40

AIAgent場景

2018-07-06 05:05:07

2024-02-20 12:09:32

模式工廠方法接口

2024-02-18 12:36:09

2024-02-22 12:13:49

適配器模式代碼

2010-09-15 13:35:25

SwingHibernateStruts
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级做a爰片性色毛片16 | 日韩高清中文字幕 | 午夜资源 | 国产一区二区 | 91社影院在线观看 | 久久久久国产一区二区三区四区 | 久久国产电影 | 羞羞网站在线免费观看 | 国产在线中文字幕 | 午夜资源 | 久久电影一区 | 色永久 | 爱爱爱av| 一级全黄少妇性色生活免费看 | 色婷婷久久久亚洲一区二区三区 | 国产精品18hdxxxⅹ在线 | 久久精品在线 | 欧美片网站免费 | 日韩欧美在线观看 | 亚洲欧美视频一区 | 一二区成人影院电影网 | 在线观看中文字幕亚洲 | 久久99深爱久久99精品 | 亚洲一区二区免费 | 久久久久国产精品 | 欧美一区二区另类 | 激情欧美一区二区三区中文字幕 | 日韩精品一区二区三区中文在线 | 日韩在线精品视频 | 国产精品国产三级国产aⅴ中文 | 欧美一区二区三区四区视频 | 日韩精品视频在线免费观看 | 久久精品视频网站 | 国产成人小视频 | 成人免费在线观看 | 精品在线观看一区二区 | 国产精久久久久久久 | 日韩在线一区二区 | 国产欧美精品在线 | 91成人在线 | 中文字幕亚洲无线 |