资讯专栏INFORMATION COLUMN

把「策略模式」应用到实际项目中

LeviDing / 611人阅读

摘要:阅读原文把策略模式应用到实际项目中无论你知不知道这个设计模式,但必定在项目中都似曾相识。文件存储的方式不同,同时文件的获取和删除也不同保存,获取,删除后的响应也是相同的,也不考虑了。此时引入是解决问题的最佳方式。

阅读原文:把「策略模式」应用到实际项目中

无论你知不知道这个设计模式,但必定在项目中都似曾相识。倘若仅仅聊理论必然枯燥乏味,只有理论和实战相结合方可达到人剑合一的境界。

首先,我来说个需求,倘若是你遇到该如何做?你可停留几分钟,想出你的解决方式,可在下方留言,说出你的想法。

需求

用户有文件上传的需求,而我们要负责对文件进行存储,由于我们的系统可能会多带带给个别客户私有化部署(部署尽量少依赖中间件能服务等),同时我们也会自己运营成为自己的SaaS服务(保证服务的高可用等)。

所以我们有两点需求:

要在SaaS版本中将文件存入分布式存储系统fastDfs中

客户的私有部署中将文件​存储在数据库中

思路 寻找异同点

文件上传过程这个无论什么版本部署都是一样的,所以暂不考虑。

文件存储的方式不同,同时文件的获取和删除也不同

保存,获取,删除后的响应也是相同的,也不考虑了。

开始抽象

当前我们考虑的就是文件的存储,获取和删除了。同样的行为,不同的实现,我们必定想到定义一个接口:

/**
 * 文件存储接口
 * Identify表示文件的唯一标识,可任意类型
 * T 表示 上传下载的返回类型,可任意类型
 *
 * @author flyhero
 * @date 2019-02-01 11:18 AM
 */
public interface IStorageService {

    /**
     * 上传文件
     *
     * @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 {

    @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 {

    @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的作用,是为了避免高层直接与策略接口直接交互,为什么呢?因为我们策略模式接口功能相对比较单一,而有些高层模块可能需要一些比较复杂的交互。

若直接调用接口,则需要对每个实现增加逻辑;

若直接调用前,执行增强逻辑,那么多个地方使用时,会存在重复增强逻辑,并可能忘掉。

此时引入Context是解决问题的最佳方式。

而我们的FileServiceImpl就相当于Context的作用,由于我们使用Spring框架且使用了三层架构,暴露上传文件、下载文件、删除文件是在controller层三个不同的方法中(或不同的controller中),为了避免几个地方使用的存储策略不同,我直接在Context中来指定使用的策略,当需要切换时也非常方便,只需要更改IStorageService的注解即可。

总结 优点

策略实现类可自由切换

易于扩展,若还有新的策略只要新增策略接口一个实现类即可

不必使用条件语句进行决定使用哪个策略

缺点

策略类一旦增多,调用者要清楚的知道各种策略的区别

如果你有不同的看法,还望不吝指教。

更多精彩技术文章尽在微信公众号:码上实战

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74282.html

相关文章

  • 一文理清21种设计模式:用实例分析和对比

    摘要:设计模式无论是对于最底层的的编码实现还是较高层的架构设计都有着重要的指导作用。所谓光说不练假把式,今天我就把项目中常见的应用场景涉及到的主要设计模式及其相关设计模式总结一下,用实例分析和对比的方式在一片文章中就把最常见的种设计模式梳理清楚。 设计模式无论是对于最底层的的编码实现还是较高层的架构设计都有着重要的指导作用。所谓光说不练假把式,今天我就把项目中常见的应用场景涉及到的主要设计模...

    PrototypeZ 评论0 收藏0
  • 常见设计模式的定义,应用场景和方法

    摘要:命令模式的由来,其实是回调函数的一个面向对象的替代品,命令模式早已融入到了语言之中。 模式是对某情景下,针对某种问题的某种解决方案。而一个设计模式是用来解决一个经常出现的设计问题的经验方法。这么说来,每个模式都可能有着自己的意图,应用场景,使用方法和使用后果。本文的行文思路和目的皆在于了解各个模式的定义,应用场景和用实例说明如何在前端开发中使用。 本文所设计到的概念和实例大多来自《H...

    xuxueli 评论0 收藏0
  • JS设计模式——策略模式

    摘要:版本策略模式在上个例子中虽然初步实现了策略模式,但是是仿照的传统面向对象语言,而的实现更为简单,直接把原来的实例定义成函数,原先的类用函数来委托。 1. 介绍 策略模式是JS设计模式中一大重要的模式有着广泛的应用 2. 定义 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换 3. 应用 根据等级、工资计算奖金等类似情况、使用不同的动画效果、表单验证等 4. 思想 把算法实...

    Jrain 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<