JAVA设计模式那些事

设计模式是众多软件开发工程师经过长时间的编码和应用总结出来的,解决特定问题的一系列方案。现行大部分教材在介绍设计模式时,有些会因为案例脱离实际应用场景而令人难以理解,有些又会因为场景简单而显得有些小题大做。本文采用“师生对话”这种相对诙谐的形式去讲解常用设计模式的应用。希望能对想提升系统设计能力的同学有所帮助或启发。

JAVA设计模式那些事

引言

话说这是在程序员世界里一对师徒的对话:

小明:老师,我最近在写代码时总感觉自己的代码很不优雅,有什么办法能优化吗?

老师:可以考虑通过教材系统学习,从注释、命名、方法和异常等多方面实现整洁代码。

小明叹气道:我想说的是,我的代码是符合各种编码规范的,但是从实现上却总是感觉不够简洁,而且总是需要反复修改!

老师看了看小明的代码说:我明白了,这是程序设计上的缺陷。总结就是抽象不够、可读性低、不够健壮。

小明:对对对,那怎么能迅速提高代码的可读性、健壮性、扩展性呢?

老师敲了敲小明的头:年轻人不要太浮躁,做什么事都要脚踏实地,没有什么方法能让你立刻成为系统设计专家。但是对于你的问题,设计模式应该可以帮到你。

小明:设计模式?”小明一脸懵逼“

奖励的发放策略

老师问小明:你知道活动营销吗?

小明:这我知道,活动营销是指企业通过参与社会关注度高的已有活动,或整合有效的资源自主策划大型活动,从而迅速提高企业及其品牌的知名度、美誉度和影响力,常见的比如有抽奖、红包等。

老师点点头:是的。我们假设现在就要做一个营销,需要用户参与一个活动,然后完成一系列的任务,最后可以得到一些奖励作为回报。活动的奖励包含手机、酒旅和美食等多种品类券,现在需要你帮忙设计一套奖励发放方案。因为之前有过类似的开发经验,拿到需求的小明二话不说开始了编写起了代码。

很快小明写好了Demo,然后发给老师看。

/**
 * 奖励服务类
 */
public class RewardService  {
    //手机优惠劵
    private PhoneService phoneService = new PhoneService();
    //酒店优惠卷
    private HotelService hotelService = new HotelService();
    //美食优惠劵
    private FoodService foodService = new FoodService();

    // 使用对入参的条件判断进行发奖
    public void issueReward(String rewardType, Object ... params) {
        if ("Phone".equals(rewardType)) {
            phoneService.grant();
        } else if ("Hotel".equals(rewardType)) {
            hotelService.grant();
        } else if ("Food".equals(rewardType)) {
            foodService.grant();
        } else {
            throw new IllegalArgumentException("rewardType error!");
        }
    }


}

老师问道:假如我们即将接入新的打车优惠券,这是否意味着你必须要修改这部分代码?

小明陷入了思考之中,一时间没法回答。

经验丰富的老师一针见血地指出了代码设计问题:“你这段代码有两个主要问题,一是不符合开闭原则,可以预见,如果后续新增品类券的话,需要直接修改主干代码,而我们提倡代码应该是对修改封闭的;二是不符合迪米特法则,发奖逻辑和各个下游接口高度耦合,这导致接口的改变将直接影响到代码的组织,使得代码的可维护性降低。”

小明恍然大悟:那我将各个同下游接口交互的功能抽象成单独的服务,封装其参数组装及异常处理,使得发奖主逻辑与其解耦,是否就能更具备扩展性和可维护性?

“这是个不错的思路。之前跟你介绍过设计模式,这个案例就可以使用策略模式适配器模式来优化。”

小明借此机会学习了这两个设计模式。首先是策略模式:

JAVA设计模式那些事

策略模式定义一系列的算法,并将每一个算法封装起来,使它们可以相互替换。策略模式通常包含以下角色:

  • 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

适配器模式,将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式包含以下主要角色:

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

结合优化思路,小明首先设计出了策略接口,并通过适配器的思想将各个下游接口类适配成策略类:

策略接口

public interface Strategy {
    //奖励发放
    void issue(Object... params);
}

手机优惠劵策略

public class PhoneService implements Strategy {
    @Override
    public void issue(Object... params) {
        System.out.println("手机优惠劵奖励发送");

    }
}

酒店优惠劵策略

public class HotelService implements Strategy{
    @Override
    public void issue(Object... params) {
        System.out.println("酒店优惠劵奖励发放");

    }
}

美食优惠劵策略

public class FoodService implements Strategy{

    @Override
    public void issue(Object... params) {
        System.out.println("美食优惠劵奖励发放");
    }
}

创建策略模式的环境类,并供奖励服务调用

public class StrategyContext {
    public static Strategy getStrategy(String rewardType) {
        switch (rewardType) {
            case "Phone":
                return new PhoneService();
            case "Hotel":
                return new HotelService();
            case "Food":
                return new FoodService();
            default:
                throw new IllegalArgumentException("rewardType error!");
        }
    }
}

优化后奖励服务

/**
 *优化后策略服务
 */
public class RewardService  {
    public void issueReward(String rewardType, Object ... params) {
        Strategy strategy = StrategyContext.getStrategy(rewardType);
        strategy.issue(params);
    }
}
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章