把策略模式應用到實際專案中
無論你知不知道這個設計模式,但必定在專案中都似曾相識。倘若僅僅聊理論必然枯燥乏味,只有理論和實戰相結合方可達到人劍合一的境界。
首先,我來說個需求,倘若是你遇到該如何做?你可停留幾分鐘,想出你的解決方式,可在下方留言,說出你的想法。
需求
使用者有檔案上傳的需求,而我們要負責對檔案進行儲存,由於我們的系統可能會單獨給個別客戶私有化部署(部署儘量少依賴中介軟體能服務等),同時我們也會自己運營成為自己的SaaS服務(保證服務的高可用等)。
所以我們有兩點需求:
1. 要在SaaS版本中將檔案存入分散式儲存系統fastDfs中
2. 客戶的私有部署中 將檔案 儲存在資料庫中
思路
尋找異同點
-
檔案上傳過程這個無論什麼版本部署都是一樣的,所以暫不考慮。
-
檔案儲存的方式不同,同時檔案的獲取和刪除也不同
-
儲存,獲取,刪除後的響應也是相同的,也不考慮了。
開始抽象
當前我們考慮的就是檔案的儲存,獲取和刪除。同樣的行為,不同的實現,我們必定想到定義一個介面:
/** * 檔案儲存介面 * Identify表示檔案的唯一標識,可任意型別 * T 表示 上傳下載的返回型別,可任意型別 * * @author flyhero * @date 2019-02-01 11:18 AM */ public interface IStorageService<Identify, T> { /** * 上傳檔案 * * @param file * @return */ T upload(MultipartFile file); /** * 下載檔案 * * @param identify * @return */ T download(Identify identify); /** * 刪除檔案 * * @param identify */ void delete(Identify identify); }
兩種不同的實現
-
儲存FastDfs
@Slfj @Service("fastDfsServiceImpl") public class FastDfsServiceImpl implements IStorageService<String,FileVo> { @Override @Transactional(rollbackFor = Exception.class) public FileVo upload(MultipartFile multipartFile){ logger.info("儲存在fastDfs……"); } @Override public FileVo download(String hash) { logger.info("從fastDfs下載檔案"); return null; } @Override @Transactional(rollbackFor = Exception.class) public void delete(String hash) { logger.info("從fastDfs刪除檔案"); } }
-
儲存 資料庫
@Slfj @Service("databaseServiceImpl") public class DatabaseServiceImpl implements IStorageService<String,FileVo> { @Override @Transactional(rollbackFor = Exception.class) public FileVo upload(MultipartFile file) { logger.info("儲存在database……"); return null; } @Override public FileVo download(String hash) { logger.info("從database下載檔案"); return null; } @Override public void delete(String hash) { logger.info("從database刪除檔案"); } }
-
呼叫
@Service public class FileServiceImpl implements FileService { //同一個介面根據不同的名稱呼叫不同的實現 //@Qualifier("databaseServiceImpl") @Qualifier("fastDfsServiceImpl") @Autowired private IStorageService storageService; public void save(MultipartFile file){ if (null == file) { throws new Exception("檔案不能為空"); } FileVo fileVo = storageService.upload(file); } }
疑惑
可能有人會說了:這怎麼和我瞭解的策略模式不一樣啊,策略模式不是這樣的嗎?
你說的對!但這是在沒有任何框架下的設計模式,而我們現在普遍使用的都是Spring框架,那麼標準的策略模式中的Context去哪裡了?
-
引入Context的作用
首先我們要知道 引入Context的作用,是 為了避免高層直接與策略介面直接互動 ,為什麼呢?因為我們策略模式介面功能相對比較單一,而有些高層模組可能需要一些比較複雜的互動。
1.若直接呼叫介面,則需要對每個實現增加邏輯;
2.若直接呼叫前,執行增強邏輯,那麼多個地方使用時,會存在重複增強邏輯,並可能忘掉。
此時引入Context是解決問題的最佳方式。
而我們的FileServiceImpl就相當於Context的作用,由於我們使用Spring框架且使用了三層架構,暴露上傳檔案、下載檔案、刪除檔案是在controller層三個不同的方法中(或不同的controller中),為了避免幾個地方使用的儲存策略不同,我直接在Context中來指定使用的策略,當需要切換時也非常方便,只需要更改IStorageService的註解即可。
總結
優點
-
策略實現類可自由切換
-
易於擴充套件,若還有新的策略只要新增策略介面一個實現類即可
-
不必使用條件語句進行決定使用哪個策略
缺點
-
策略類一旦增多,呼叫者要清楚的知道各種策略的區別
如果你有不同的看法,還望不吝指教。
海記憶體知己,天涯若比鄰,喜歡就關注吧
喜歡就點選“好看”吧