设计模式之策略模式(如何优雅的去除if-else逻辑代码)

                          设计模式之策略模式(如何优雅的去除if-else逻辑代码)

    项目要求:

    新增一个数据接收的接口,接收来自不同渠道的数据进行个性化的处理。目前已知的渠道有360、百度,以后还会不断扩展渠道,要求必须在同一个接口处理所有数据接收请求。

    大多数的实现是这样的:

    

/**
	 * 点击数据匹配接口
	 */
	@GetMapping(value = "/matchData", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public JsonResult matchData(@RequestParam("imei") String imei, @RequestParam("event_type") String event_type, @RequestParam("channelid") String channelid) {
		try {
			Map<String,Object> map=new HashMap<String,Object>(2);
			map.put("imei", imei);
			map.put("event_type", event_type);
			if("01".equals(channelid)) {
				do360MatchData(map);
			}else if("02".equals(channelid)) {
				doBaiduMatchData(map);
			}else {
				doSomethingElse(map);
			}
			return JsonResult.getSuccess("点击数据匹配");
		} catch (Exception e) {
            logger.error("点击数据匹配失败:" + e.getMessage(), e);
			return JsonResult.getInnerFail("9999", "点击数据匹配失败");
		}

    以上代码实现有如下的缺点:

  • 不易于扩展,增加一个新的渠道需要改变原有的代码,不符合开放封闭原则
  • 使用多重条件选择语句,不符合面向对象设计思想
  • 代码柔和在一起,不利于阅读和维护,不符合单一职责原则。 

   针对以上代码的缺点我们有啥好的改进方式吗?

   有!我们可以利用策略模式来消除臃肿复杂的if-else。

   

   

策略模式定义

定义了一些平行的算法组,分别封装起来,算法之间可以相互替换,此模式使算法的变化独立于调用者之外

算法结构

  • 抽象策略角色(Strategy):这是一个抽象类或者接口,将算法的行为进行封装,所有的策略类都要实现该接口
  • 具体策略角色(ConcreteStrategy):封装了具体的算法和行为
  • 环境角色(Context):持有一个抽象策略的引用,并提供统一调用的入口

 

 代码实现:

1:首先定义抽象的数据策略接口

package com.zte.service.primary;

import java.util.Map;

public interface IMatchServcie {
	
	
	
	void match(Map<String,Object> map);
	
	String getChannelId();

}

其中 match方法是执行具体匹配数据逻辑的接口,而getChannelId方法则有妙用,请往下看

2:定义具体策略角色360数据匹配角色

package com.zte.service.primary;

import java.util.Map;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;
import com.zte.model.TAdvertisementMatching;
import com.zte.model.TAdvertisementThrowin;
import com.zte.utils.DateUtil;

@Service("match360Service")
public class Match360ServiceImpl implements IMatchServcie {
	@Autowired
	private Logger logger;
	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private AdvertisementThrowinService advertisementThrowinService;
	
	public static final String CHANNEL360="22017001";

	@Override
	public void match(Map<String, Object> map) {
		try {
			doSomthing();
		} catch (Exception e) {
			logger.error("点击数据匹配失败:" + e.getMessage(), e);
		}

	}

	@Override
	public String getChannelId() {

		return CHANNEL360;
	}

}

 该类实现了抽象策略接口,实现了默认的方法,其中match方法实现自己的业务逻辑,getChannelId方法返回一个具体的常量,还记得我们的需求吗?根据不同的渠道实现不同的数据匹配逻辑。我们如何实现,就是通过这个常量来匹配到具体的策略角色去处理。

3:环境角色类创建

package com.zte.service.primary;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;


@Service
public class MatchStrategyPattern {
	@Resource
    private List<IMatchServcie> matchServcieList;

	public void match(String channelId,Map<String,Object> map) {
		 Optional<IMatchServcie> optional = matchServcieList.stream()
                 .filter(service -> service.getChannelId().equals(channelId))
                 .findFirst();
		 optional.ifPresent(op->{optional.get().match(map);});
	}
	
	

}

从上述代码我们可以看到,我们利用spring的自动注入,注入了一个类型位抽象策略接口的List,程序会自动将类型为IMatchService的具体策略角色类注入到List中。而match方法则是暴露给外部的统一匹配方法。该方法通过外部传入的渠道id字段通过接口方法getChaennlId返回的渠道id进行匹配,如果匹配中了就选用该角色进行逻辑处理。达到动态匹配的效果。

 

4:这个时候如果我们要加入一个新的数据匹配角色,我们只需要新建一个新类实现抽象策略方法,然后的然后程序就可以自动的跑起来,无需修改任何现有的文件。程序中也没有了那个令人烦厌的if-else。

package com.zte.service.primary;

import java.util.Map;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSONObject;
import com.zte.model.TAdvertisementMatching;
import com.zte.model.TAdvertisementThrowin;
import com.zte.utils.DateUtil;

@Service("matchBaiduService")
public class MatchBaiduServiceImpl implements IMatchServcie {
	@Autowired
	private Logger logger;
	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private AdvertisementThrowinService advertisementThrowinService;
	
	public static final String CHANNELBAIDU="22017002";

	@Override
	public void match(Map<String, Object> map) {
		try {
			doSomthing();
		} catch (Exception e) {
			logger.error("点击数据匹配失败:" + e.getMessage(), e);
		}

	}

	@Override
	public String getChannelId() {

		return CHANNELBAIDU;
	}

}

策略模式的优缺点

优点

  • 易于扩展,增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合开放封闭原则
  • 避免使用多重条件选择语句,充分体现面向对象设计思想
  • 策略类之间可以自由切换,由于策略类都实现同一个接口,所以使它们之间可以自由切换
  • 每个策略类使用一个策略类,符合单一职责原则
  • 客户端与策略算法解耦,两者都依赖于抽象策略接口,符合依赖反转原则
  • 客户端不需要知道都有哪些策略类,符合最小知识原则

缺点

  • 策略模式,当策略算法太多时,会造成很多的策略类
  • 客户端不知道有哪些策略类,不能决定使用哪个策略类,这点可以通过本文中的方式解决,也可以考虑使用IOC容器和依赖注入的方式来解决
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码中的条件语句if-else过于复杂时,可以考虑使用设计模式代替if-else语句,提高代码的可读性和可维护性。以下是一些常见的设计模式,可以用来代替if-else语句: 1. 工厂模式(Factory Pattern):通过工厂方法创建对象,而不是使用条件语句来直接创建对象。这样可以避免在代码中使用大量的if-else语句,同时也可以很方便地添加新的对象类型。 2. 状态模式(State Pattern):将复杂的状态判断逻辑封装到不同的状态类中,避免在代码中使用大量的if-else语句。可以很方便地添加新的状态类型,也可以方便地维护和扩展状态的行为。 3. 策略模式(Strategy Pattern):将不同的算法封装到不同的策略类中,通过选择不同的策略类来实现不同的行为。这样可以避免在代码中使用复杂的if-else语句,同时也可以很方便地添加新的算法类型。 4. 观察者模式(Observer Pattern):将一个对象的状态变化通知给多个观察者对象,避免在代码中使用大量的if-else语句。可以很方便地添加新的观察者对象,也可以方便地维护和扩展观察者的行为。 5. 责任链模式(Chain of Responsibility Pattern):将多个处理对象组成一个链,每个处理对象都可以处理请求,如果一个对象不能处理请求,则将请求传递给下一个处理对象。这样可以避免在代码中使用大量的if-else语句,同时也可以很方便地添加新的处理对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值