策略模式简单使用

策略模式简单使用

问题

在设计账户系统的过程中遇到这样一个问题,就是当第三方账户需要根据第三方账户的类型来当前的用户id和第三方的unionId进行一个绑定操作。
如果一般的做法呢就是写很多的if else通过判断不同的账户类型,来决定进行哪种第三方绑定的操作。

解决方案

下面是使用策略模式的做法,下面代码演示,只需关注策略模式的流程和实现,语法上不必深究

首先定义一个 策略接口

package com.third;
public interface ThirdInfoInterfaceStrategy {
    void updateUserInfo(String unionId, TblUserInfo userInfo);
}

接着实现具体的三方绑定操作
可能有微信的方式

package com.third;
public class WechatUserInfoStrategy implements ThirdInfoInterfaceStrategy {
    @Override
    public void updateUserInfo(String unionId, TblUserInfo userInfo) {
        userInfo.setWechatBind(1);
        userInfo.setWechatUnionid(unionId);
        userInfo.setLoginMethod(ThirdAccountOperator.WECHAT_LOGIN_METHOD);
    }
}

可能有苹果的方式

package com.third;
public class AppleUserInfoStrategy implements ThirdInfoInterfaceStrategy {
    @Override
    public void updateUserInfo(String unionId, TblUserInfo userInfo) {
        userInfo.setAppleBind(1);
        userInfo.setAppleUserId(unionId);
        userInfo.setLoginMethod(ThirdAccountOperator.APPLE_LOGIN_METHOD);
    }
}

可能有淘宝的方式

package com.third;
public class TaobaoUserInfoStrategy implements ThirdInfoInterfaceStrategy {
    @Override
    public void updateUserInfo(String unionId, TblUserInfo userInfo) {
        userInfo.setTaobaoBind(1);
        userInfo.setTaobaoUserId(unionId);
        userInfo.setLoginMethod(ThirdAccountOperator.TAOBAO_LOGIN_METHOD);
    }
}

最后定义一个上下文类,统一执行所有策略绑定操作
Context类意义,使得策略的行为对外操作起来更为统一,注意策略模式是一个行为行的设计模式,
关注点在执行行为的那个方法,而不用关心,具体的策略方法,
当然了我觉得如果策略的行为特别简单,在决定要使用哪种策略的时候也可以直接用。

package com.third;
public class ThirdInfoBindContext{
	
	// 使用组合的方式, 降低对行为实现类型的依赖
	private ThirdInfoInterfaceStrategy thirdInfoInterfaceStrategy;

	// 也可以通过构造方法的方式将具体策略传入
	public void setThirdInfoInterfaceStrategy(ThirdInfoInterfaceStrategy thirdInfoInterfaceStrategy){
		this.thirdInfoInterfaceStrategy = thirdInfoInterfaceStrategy;
	}

	// 
	public void bind(String unionId,TblUserInfo userInfo){
		// 策略执行前做
		。。。。
		thirdInfoInterfaceStrategy.updateUserInfo(unionId,userInfo);

		// 策略执行后
		。。。。。。
	}
}

// 简单调用,版本一

public class Client{
	public static void main(String[] args) {
	
		// 调用时才知道要使用具体哪个策略类,把变化延时到了使用的地方
		// 在使用的时候,对于有没有这个类,其实是不关心的,
		ThirdInfoInterfaceStrategy userInfoStrategy = new WechatUserInfoStrategy();


		// 下面这部分代码都可以保持稳定,不变
		ThirdInfoBindContext context = new ThirdInfoBindContext(userInfoStrategy);
		String unionId = "123";
		TblUserInfo userInfo = new TblUserInfo();
		// 绑定的动作不会随着策略的变化而改变
		context.bind(unionId,userInfo);
	}
}

// 通过反射获取具体策略对象,版本二

public class Client{
	public static void main(String[] args) {
		
		// 这个可以实际策略类的名称配置文件来进行定义,这样就可以动态的运行想要调用的策略了
		String strategyName = "com.third.WechatUserInfoStrategy";

		Class<?>   aClass = Class.forName(strategyName);
		ThirdInfoInterfaceStrategy userInfoStrategy = (ThirdInfoInterfaceStrategy) aClass.newInstance();

		// 下面这部分代码都可以保持稳定,不变
		ThirdInfoBindContext context = new ThirdInfoBindContext(userInfoStrategy);
		String unionId = "123";
		TblUserInfo userInfo = new TblUserInfo();
		// 绑定的动作不会随着策略的变化而改变
		context.bind(unionId,userInfo);

	}
}

// 配置文件+反射调用,版本三

public class Client{
	public static void main(String[] args) {
		
		// 用户登录的时候App端会将当前登录的第三方类型的参数传入type
		// 我们可以根据参数的类型,来选择具体的策略,并且将type对应的策略名称写在配置文件中
		// 实际使用起来就变成了下面这样
		// 。。。。 省略前面的步骤		
		// 读取配置文件,将type和strategyName用一个Map存储
		Map<String,String> config;
		String strategyName = config.get(type);

		Class<?> aClass = Class.forName(strategyName);
		ThirdInfoInterfaceStrategy userInfoStrategy = (ThirdInfoInterfaceStrategy) aClass.newInstance();

		// 下面这部分代码都可以保持稳定,不变
		ThirdInfoBindContext context = new ThirdInfoBindContext(userInfoStrategy);
		String unionId = "123";
		TblUserInfo userInfo = new TblUserInfo();
		// 绑定的动作不会随着策略的变化而改变
		context.bind(unionId,userInfo);
	}
}

配置

key[0] = weixin
value[0] = com.third.WechatUserInfoStrategy 
key[1] = apple
value[1] = com.third.AppleUserInfoStrategy 
.....

在版本三中实现了全流程代码不改动,完全适应业务,当新的第三方登录方式增加时,只需要增加代码的具体策略,和配置文件中的类型和策略名称即可。
这种做法可能在现如今这个jar包部署整个服务时候体现不出优势,因为我们不能向正在执行的jar包中添加其他的.class文件。
但在我接触的C# 项目中,这种反射+配置的做法,好处却时十分的明显,当新加一个功能时往往只需要在项目目录中加一个写好的.dll文件,
再将当前项目中的配置文件添加相关配置,即可完成功能的添加,使用起来十分的方便。

总结一下

  • 1.当有许多if-else出现时,可以考虑使用策略模式
  • 2.在Context中,使用组合的方式来获取具体的策略类,是一个值得学习的地方,即组合优于继承。
  • 3.很多设计模式的出现,是因为变化太多,但是设计模式的意义并不是完全消灭变化,而是把变化像贴屏保的时候挤气泡一样,
    把变化都集中在一个地方,这样更容易被管理,比如配置中心就应对变化的一个好去处。
  • 4.策略模式虽然做到了很好的隔离性和拓展性,但是随着策略的增多,类会变的越来越多,这个问题我也遇到了,下一次来谈一下我面对的策略膨胀和解决方案。

猜你喜欢

转载自blog.csdn.net/qq_36838406/article/details/108271667