把「策略模式」應用到實際項目中

閱讀原文:把「策略模式」應用到實際項目中java

不管你知不知道這個設計模式,但一定在項目中都似曾相識。假若僅僅聊理論必然枯燥乏味,只有理論和實戰相結合方可達到人劍合一的境界。面試

首先,我來講個需求,假若是你遇到該如何作?你可停留幾分鐘,想出你的解決方式,可在下方留言,說出你的想法。數據庫

需求

用戶有文件上傳的需求,而咱們要負責對文件進行存儲,因爲咱們的系統可能會單獨給個別客戶私有化部署(部署儘可能少依賴中間件能服務等),同時咱們也會本身運營成爲本身的SaaS服務(保證服務的高可用等)。設計模式

因此咱們有兩點需求:微信

  1. 要在SaaS版本中將文件存入分佈式存儲系統fastDfs中架構

  2. 客戶的私有部署中將文件​存儲在數據庫中框架

思路

尋找異同點

  1. 文件上傳過程這個不管什麼版本部署都是同樣的,因此暫不考慮。分佈式

  2. 文件存儲的方式不一樣,同時文件的獲取和刪除也不一樣ide

  3. 保存,獲取,刪除後的響應也是相同的,也不考慮了。spa

開始抽象

當前咱們考慮的就是文件的存儲,獲取和刪除了。一樣的行爲,不一樣的實現,咱們一定想到定義一個接口:

/** * 文件存儲接口 * 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的註解便可。

總結

優勢

  • 策略實現類可自由切換
  • 易於擴展,若還有新的策略只要新增策略接口一個實現類便可
  • 沒必要使用條件語句進行決定使用哪一個策略

缺點

  • 策略類一旦增多,調用者要清楚的知道各類策略的區別

若是你有不一樣的見解,還望不吝指教。

發現這個面試視頻不錯,分享給你們,公衆號回覆: 面試視頻 和 架構師

20190424123323.jpg

更多精彩技術文章盡在微信公衆號:碼上實戰

相關文章
相關標籤/搜索