不管你知不知道這個設計模式,但一定在項目中都似曾相識。假若僅僅聊理論必然枯燥乏味,只有理論和實戰相結合方可達到人劍合一的境界。面試
首先,我來講個需求,假若是你遇到該如何作?你可停留幾分鐘,想出你的解決方式,可在下方留言,說出你的想法。數據庫
用戶有文件上傳的需求,而咱們要負責對文件進行存儲,因爲咱們的系統可能會單獨給個別客戶私有化部署(部署儘可能少依賴中間件能服務等),同時咱們也會本身運營成爲本身的SaaS服務(保證服務的高可用等)。設計模式
因此咱們有兩點需求:微信
要在SaaS版本中將文件存入分佈式存儲系統fastDfs中架構
客戶的私有部署中將文件存儲在數據庫中框架
文件上傳過程這個不管什麼版本部署都是同樣的,因此暫不考慮。分佈式
文件存儲的方式不一樣,同時文件的獲取和刪除也不一樣ide
保存,獲取,刪除後的響應也是相同的,也不考慮了。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);
}
複製代碼
####兩種不一樣的實現
@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是解決問題的最佳方式。
而咱們的FileServiceImpl就至關於Context的做用,因爲咱們使用Spring框架且使用了三層架構,暴露上傳文件、下載文件、刪除文件是在controller層三個不一樣的方法中(或不一樣的controller中),爲了不幾個地方使用的存儲策略不一樣,我直接在Context中來指定使用的策略,當須要切換時也很是方便,只須要更改IStorageService的註解便可。
若是你有不一樣的見解,還望不吝指教。
發現這個面試視頻不錯,分享給你們,公衆號回覆: 面試視頻 和 架構師
20190424123323.jpg
更多精彩技術文章盡在微信公衆號:碼上實戰