設計模式不該該停留於理論,跟具體業務結合,它纔會變得更香~git
設計模式咱們多少都有些瞭解,可是每每也只是知道是什麼。github
在真實的業務場景中,你有用過什麼設計模式來編寫更優雅的代碼嗎?面試
咱們更多的是天天從產品經理那裏接受到新需求後,就開始MVC一把梭,面向sql編程了。算法
咱們習慣採用MVC架構,實時上是很是容易建立不少貧血對象模型,而後寫出過程式代碼。咱們使用的對象,每每只是數據的載體,沒有任何邏輯行爲。咱們的設計過程,也是從ER圖開始,以數據爲中心進行驅動設計。一個需求一個接口,從controller到service到dao,這樣日復一日的CRUD。sql
什麼設計模式?根本不存在的!數據庫
今天,咱們嘗試從經常使用設計模式(工廠模式、代理模式、模版模式)在CRUD中的可落地場景,但願能給你們帶來一些啓發。編程
設計模式(Design pattern),不是前人憑空想象的,而是在長期的軟件設計實踐過程當中,通過總結獲得的。設計模式
使用設計模式是爲了讓代碼具備可擴展性,實現高聚合、低耦合的特性。api
世上原本沒有設計模式,寫代碼的人多了,便有了設計模式。架構
過去,咱們會去學習設計模式的理論,今天,咱們嘗試從經常使用設計模式(工廠模式、代理模式、模版模式)在CRUD中的可落地場景,但願能給你們帶來一些實戰啓發。
1)工廠模式介紹
工廠模式應該是咱們最熟悉的設計模式了,不少框架都會有經典的xxxxFactory,而後經過xxxFactory.create來獲取對象。這裏不詳細展開介紹,給出一個你們耳熟能詳的工廠模式類圖應該就能回憶起來了。
工廠模式的優勢很明顯:
那麼,實際業務開發該怎麼落地使用呢?
2)需求舉例
咱們須要作一個HBase的管理系統,相似於MySQL的navicat或者workbench。
那麼有一個很重要的模塊,就是實現HBase的增刪改查。
而開源的HBase-client已經提供了標準的增刪改查的api,咱們如何集成到系統中呢?
3)簡單代碼
@RestController("/hbase/execute")
public class DemoController {
private HBaseExecuteService hbaseExecuteService;
public DemoController(ExecuteService executeService) {
this.hbaseExecuteService = executeService;
}
@PostMapping("/insert")
public void insertDate(InsertCondition insertCondition) {
hbaseExecuteService.insertDate(insertCondition);
}
@PostMapping("/update")
public void updateDate(UpdateCondition updateCondition) {
hbaseExecuteService.updateDate(updateCondition;
}
@PostMapping("/delete")
public void deleteDate(DeleteCondition deleteCondition) {
hbaseExecuteService.deleteData(deleteCondition);
}
@GetMapping("/select")
public Object selectDate(SelectCondition selectCondition) {
return hbaseExecuteService.seletData(selectCondition);
}
}
每次增長一個功能,都須要從controller到service寫一遍相似的操做。
還須要構建不少相關dto進行數據傳遞,裏面會帶着不少重複的變量,好比表名、列名等查詢條件。
4)模式應用
抽象接口
public interface HBaseCommand {
/**
* 執行命令
*/
ExecResult execute();
}
抽象類實現公共配置
public class AbstractHBaseCommand implements HBaseCommand {
Configuration configuration;
AbstractHBaseCommand(ExecuteCondition executeCondition) {
this.configuration = getConfiguration(executeCondition.getResourceId());
}
private Configuration getConfiguration(String resourceId) {
Configuration conf = HBaseConfiguration.create();
//作一些配置相關事情
//。。。。
return conf;
}
@Override
public ExecResult execute() {
return null;
}
}
工廠類生產具體的命令
public class CommandFactory {
private ExecuteCondition executeCondition;
public CommandFactory(ExecuteCondition executeCondition) {
this.executeCondition = executeCondition;
}
public HBaseCommand create() {
HBaseCommand hBaseCommand;
switch (ExecuteTypeEnum.getTypeForName(executeCondition.getQueryType())) {
case Get:
return new GetCommand(executeCondition);
case Put:
return new PutCommand(executeCondition);
case Delete:
return new DeleteCommand(executeCondition);
}
return null;
}
}
一個執行接口,執行增刪改查多個命令
public class ExecuteController {
private ExecuteService executeService;
public ExecuteController(ExecuteService executeService) {
this.executeService = executeService;
}
@GetMapping
public Object exec(ExecuteCondition executeCondition) {
ExecResult execResult = executeService.execute(executeCondition);
return transform(execResult);
}
}
service調用工廠來建立具體的命令進行執行
@Service
public class ExecuteService {
public ExecResult execute(ExecuteCondition executeCondition) {
CommandFactory factory = new CommandFactory(executeCondition);
HBaseCommand command = factory.create();
return command.execute();
}
}
每次添加一個新的命令,只須要實現一個新的命令相關內容的類便可
1) 模式介紹
代理模式也是你們很是熟悉的一種模式。
它給一個對象提供一個代理,並由代理對象控制對原對象的引用。它使得用戶不能直接與真正的目標對象通訊。
代理對象相似於客戶端和目標對象之間的中介,能發揮比較多做用,好比擴展原對象的能力、作一些切面工做(打日誌)、限制原對象的能力,同時也在必定程度上面減小了系統的耦合度。
2)需求舉例
如今已經有一個client對象,實現了若干方法。
如今,有兩個需求:
3)簡單代碼
對本來的類進行修改
4)模式應用
對於方法A的再也不支持,其實有挺多辦法的,繼承或者靜態代理均可以。
靜態代理代碼:
public class ConnectionProxy implements Connection {
private Connection connection;
public ConnectionProxy(Connection connection) {
this.connection = connection;
}
@Override
public Admin getAdmin() throws IOException {
//拋出一個異常
throw new UnsupportedOperationException();
}
@Override
public boolean isClosed() {
return connection.isClosed();
}
@Override
public void abort(String why, Throwable e) {
connection.abort(why, e);
}
}
對於每一個方法的先後計算埋點,可使用動態代理進行實現。
public class TableProxy implements InvocationHandler {
private Object target;
public TableProxy(Object target) {
this.target = target;
}
/**
* 獲取被代理接口實例對象
*
* @param <T>
* @return
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long current = System.currentTimeMillis();
Object invoke;
try {
invoke = method.invoke(target, args);
} catch (Throwable throwable) {
throw throwable;
}
long cost = System.currentTimeMillis() - current;
System.out.println("cost time: " + cost);
return invoke;
}
}
1) 模式介紹
定義一個操做中的流程框架,而將一些流程中的具體步驟延遲到子類中實現。
模板方法使得子類能夠不改變一個流程框架下,經過重定義該算法的某些特定步驟實現自定義的行爲。
固然,最便利之處在於,咱們能夠保證一套完善的流程,使得不一樣子類明確知道本身須要實現哪些方法來完成這套流程。
2)需求舉例
其實模板方法是最容易理解的,也很是高效。
咱們最經常使用模版方法的一類需求就是工單審批流。
具體來講,假如咱們如今須要定義一套流程來實現一個工單審批,包含工單建立、審批操做、事件執行、消息通知等流程(實際上流程可能會更加複雜)。
而工單的對象很是多,能夠是一個服務的申請、一個數據庫的變動申請、或者是一個權限申請。
3)簡單代碼
每一個工單流程寫一套代碼。
4)模式應用
定義一個接口,裏面包括了若干方法
public interface ChangeFlow {
void createOrder();
boolean approval();
boolean execute();
void notice();
}
在一個流程模版中,拼接各個方法,實現完整工做流
public class MainFlow {
public void mainFlow(ChangeFlow flow) {
flow.createOrder();
if (!flow.approval()){
System.out.println("抱歉,審批沒有經過");
}
if (!flow.execute()) {
System.out.println("抱歉,執行失敗");
}
flow.notice();
}
}
而後,能夠在AbstractChangeFlow裏面實現通用的方法,好比approval、notice,你們都是同樣的邏輯。
public class AbstractChangeFlow implements ChangeFlow {
@Override
public void createOrder() {
System.out.println("建立訂單");
}
@Override
public boolean approval() {
if (xxx) {
System.out.println("審批經過");
return true;
}
return false;
}
@Override
public boolean execute() {
//交給其餘子類本身複寫
return true;
}
@Override
public void notice() {
System.out.println("notice");
}
}
最後,就根據具體的工單來實現自定義的excute()方法就好了,實現DbFlow、MainFlow就好了。
學習設計模式最重要的就是要在業務開發過程當中保持思考,在某一個特定的業務場景中,結合對業務場景的理解和領域模型的創建,才能體會到設計模式思想的精髓。
若是脫離具體的業務場景去學習或者談論設計模式,那是沒有意義的。
有人說,怎麼區分設計模式和過分設計呢?
其實很簡單。
1)業務設計初期。若是很是熟悉業務特性,理解業務迭代方向,那麼就能夠作一些簡單的設計了。
2)業務迭代過程當中。當你的代碼隨着業務的調整須要不斷動刀改動,破壞了設計模式的七大原則,尤爲是開閉原則,那麼,你就該去考慮考慮使用設計模式了。
看到這裏了,原創不易,點個關注、點個贊吧,你最好看了~
知識碎片從新梳理,構建Java知識圖譜:https://github.com/saigu/JavaKnowledgeGraph(歷史文章查閱很是方便)
掃碼關注個人公衆號「阿丸筆記」,第一時間獲取最新更新。同時能夠免費獲取海量Java技術棧電子書、各個大廠面試題。