南通市网站建设我的完,营销型网站制作,直播发布会,手工制作灯笼步骤 教程#x1f4e2; 大家好#xff0c;我是 【战神刘玉栋】#xff0c;有10多年的研发经验#xff0c;致力于前后端技术栈的知识沉淀和传播。 #x1f497; #x1f33b; CSDN入驻不久#xff0c;希望大家多多支持#xff0c;后续会继续提升文章质量#xff0c;绝不滥竽充数… 大家好我是 【战神刘玉栋】有10多年的研发经验致力于前后端技术栈的知识沉淀和传播。 CSDN入驻不久希望大家多多支持后续会继续提升文章质量绝不滥竽充数欢迎多多交流。 文章目录 写在前面的话策略模式介绍代码实现Spring 改进版本Spring 中的策略模式补充说明总结陈词 写在前面的话
近期无论是编码还是休闲阶段偶尔都会刷到关于设计模式的相关内容发掘可以整理的内容还不少就想着归纳高低给它整一个专栏。网上介绍23种设计模式的内容也不少大多枯燥而冗长这边不会重复搬砖也不会按顺序介绍所有设计模式只会从实战层面去分享几个实用的。
好了废话不多说先开始最常用的策略模式吧。
题外话
有的人认为设计模式很有用遵循了面向对象等开发原则可以提升代码复用提高可维护性便于后期的功能扩展。
有的人则认为设计模式很鸡肋业务需求直接用代码快速实现就行了哪里想这么多会导致过度设计设计反而浪费了时间成本增加了代码量对团队开发的要求也较高。
博主认为
1、设计模式在业务开发中有其独特的价值但是否使用以及如何使用需要根据具体的项目需求、团队经验和开发环境来权衡。
2、我们不要过度追求严格遵循设计模式的标准而应该贴合实际开发场景以提升可维护性和可扩展性为目的导向去合理使用设计模式。
3、在企业实战开发中框架封装人员更应该注重设计模式的复用而业务开发人员按需使用即可。
最后为什么学设计模式主要是学习一种编程思想总结起来也无非是学以致用罢了。 策略模式介绍 Tips为保证技术连贯照例先来一段技术简介了解一下。 基础概念
策略模式Strategy Pattern是一种行为设计模式它定义了一系列算法策略并将每一个算法封装起来使它们可以互相替换。策略模式使得算法的变化独立于使用算法的使用者。
策略模式的核心思想是将一组相关的算法封装成独立的策略类并通过一个上下文类来使用这些策略。这样客户端可以在运行时选择不同的策略而不需要修改上下文类的代码。
组成部分
1、策略接口Strategy定义一个公共接口所有具体策略都需要实现这个接口。
2、具体策略ConcreteStrategy实现策略接口的具体算法。
3、上下文Context持有一个策略对象的引用并通过该策略对象来调用具体的算法。
主要优势
1、灵活性可以在运行时选择不同的策略增加了系统的灵活性。
2、开闭原则可以在不修改现有代码的情况下增加新的策略。
3、清晰的职责分离将算法的实现与使用分开使得代码更加清晰。
个人理解
策略可以理解为方式/方法之类的即处理问题需要采用哪种不同的方法。
策略模式可以有效地替代 if…else 语句尤其是在需要根据不同条件选择不同算法或行为的场景中。
最典型的运用示例就是多种付款方式支付宝、微信、银联的下面代码以此展开。 代码实现
如下所示这里先上一个最普通的代码实现一下策略模式帮助大家理解整体看起来还是挺清爽的。
不过代码量并没有貌似不会比if...else少多少而且使用的时候额外还要一个个new吗
new的方式后面会改进至于代码量而言你要看这段代码在未来的易扩展性。 Tips哪里听过类似的长平之罪罪在将来。好像不是一个意思。 Step1、定义支付策略接口
public interface PaymentStrategy {void pay(int amount);
}Step2、定义具体策略类 Tips这里Component(“alipay”)注解非必须是后面Spring阶段使用。 Component(alipay)
public class Alipay implements PaymentStrategy {Overridepublic void pay(int amount) {System.out.println(使用支付宝支付: amount 元);}
}Component(wechatPay)
public class WeChatPay implements PaymentStrategy {Overridepublic void pay(int amount) {System.out.println(使用微信支付: amount 元);}
}Component(unionPay)
public class UnionPay implements PaymentStrategy {Overridepublic void pay(int amount) {System.out.println(使用银联支付: amount 元);}
}Step3、编写支付上下文类
ublic class PaymentContextCommon {private final PaymentStrategy paymentStrategy;public PaymentContextCommon(PaymentStrategy paymentStrategy) {this.paymentStrategy paymentStrategy;}public void executePayment(int amount) {paymentStrategy.pay(amount);}
}Step4、客户端测试
public static void main(String[] args) {int amount 100;// 使用支付宝支付PaymentContextCommon alipayContext new PaymentContextCommon(new Alipay());alipayContext.executePayment(amount);// 使用微信支付PaymentContextCommon weChatContext new PaymentContextCommon(new WeChatPay());weChatContext.executePayment(amount);// 使用银联支付PaymentContextCommon unionPayContext new PaymentContextCommon(new UnionPay());unionPayContext.executePayment(amount);}Spring 改进版本
针对前面的普通版本我们可以使用Spring的依赖注入功能来管理支付策略的列表会更简洁。
Step1、改进版本的支付上下文
这里采用Spring依赖注入Map的方式减少了很多new的代码量。
这边还需要给 Tips关于注入还有很多额外技巧和学问这里先不展开后续专题介绍。 public class PaymentContextSpring {private final MapString, PaymentStrategy paymentStrategies;public PaymentContextSpring(MapString, PaymentStrategy paymentStrategies) {this.paymentStrategies paymentStrategies;}public void executePayment(Integer payType, int amount) {String beanName PayTypeEnum.fromCode(payType).getImpl();PaymentStrategy strategy paymentStrategies.get(beanName);if (strategy ! null) {strategy.pay(amount);} else {System.out.println(未找到支付方式: beanName);}}
}Configuration
public class TestConfig {Beanpublic PaymentContextSpring paymentContextSpring(MapString, PaymentStrategy paymentStrategies) {return new PaymentContextSpring(paymentStrategies);}
}Step2、定义一个支付枚举类
这边用枚举好处多多清晰又明了。当然如果能接受前端直接传递bean的名称也可以不要枚举。
public enum PayTypeEnum {WEIXIN_SCAN(1, 微信扫码支付, wxScanPay),ALIPAY_SCAN(2, 支付宝扫码支付, aliScanPay),UNION_PAY(3, 银联支付, unionPay);private final Integer code;private final String desc;private final String impl;PayTypeEnum(Integer code, String desc, String impl) {this.code code;this.desc desc;this.impl impl;}public static PayTypeEnum fromCode(Integer code) {for (PayTypeEnum payType : PayTypeEnum.values()) {if (payType.getCode().equals(code)) {return payType;}}throw new IllegalArgumentException(Invalid code: code);}
}Step3、测试类改版
后续要扩展支付方式就增加一个Service和修改枚举即可。
SpringBootTest
RunWith(SpringRunner.class)
public class PaymentTestSpring {//Autowired//private PaymentContextSpring paymentContext;//这种方式也可以Testpublic void testPayment() {PaymentContextSpring paymentContext SpringUtil.getBean(PaymentContextSpring.class);int amount 100;paymentContext.executePayment(1, amount);paymentContext.executePayment(2, amount);paymentContext.executePayment(3, amount);}
}Spring 中的策略模式
在Spring框架中策略模式被广泛应用于多个模块使得框架具有高度的灵活性和可扩展性。通过这种设计开发者可以在不修改核心代码的情况下轻松地替换或扩展功能。
有几个重要的地方可以体现这一设计模式
Spring的事务管理
在Spring的事务管理中PlatformTransactionManager接口定义了事务管理的策略。不同的数据库或事务管理机制如JDBC、Hibernate、JPA等可以实现这个接口从而提供不同的事务管理策略。通过配置Spring可以在运行时选择合适的事务管理策略。
Spring的消息转换
Spring的消息转换机制如MessageConverter允许你在不同的消息格式之间进行转换。你可以定义多个具体的消息转换器如JSON、XML等并在运行时选择合适的转换器来处理消息。
Spring的缓存抽象
Spring的缓存抽象如CacheManager允许你使用不同的缓存策略如EhCache、Caffeine、Redis等。你可以通过配置选择不同的缓存实现而不需要修改使用缓存的代码。
Spring的安全框架
在Spring Security中认证和授权的策略也是通过策略模式实现的。不同的认证方式如表单登录、OAuth、LDAP等可以实现相同的接口Spring Security会根据配置选择合适的认证策略。
Spring的事件处理
Spring的事件处理机制如ApplicationListener和ApplicationEvent也可以视为策略模式的应用。不同的事件监听器可以实现相同的接口从而处理不同类型的事件。
补充说明
上述介绍Spring方式可以通过XMl、JavaBean或Profile等实现策略切换。
当然能实现目的并且扩展性强就OK了。不需要纠结这种方式是否为标准策略模式、以及策略如何切换。
只要将策略定义为一个个接口然后按需选择需要的策略就可以了。 总结陈词 本篇文章介绍了策略模式的实战应用希望可以帮助到大家。 后续会逐步分享企业实际开发中的实战经验有需要交流的可以联系博主。