如果项目中的一个页面跳转功能存在10个以上的if else判断,想要做一下整改
一、什么是策略模式
策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理,最终可以实现解决多重If判断问题。
1.环境(Context)角色:持有一个Strategy的引用。
2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
(定义策略接口→实现不同的策略类→利用多态或其他方式调用策略。)
二、策略模式优缺点
优点:
算法可以*切换(高层屏蔽算法,角色*切换)
避免使用多重条件判断(如果算法过多就会出现很多相同的判断,很难维护)
扩展性好(可*添加取消算法,而不影响整个功能)
缺点:
策略数量增多(每一个策略类复用性小,如果需要增加算法,就只能新增类)
所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其他模式来补充,比如工厂模式、代理模式)
三、代码示例
1.定义共同的方法和行为
package com.ultiwill.strategy;
public interface PayStrategy {
/**
* 共同的行为方法
* @return
*/
String toPayHtml();
}
2. 三种具体策略的实现 (阿里支付, 微信支付, 小米支付)
package com.ultiwill.strategy.impl;
import com.ultiwill.strategy.PayStrategy;
/**
* @author chong.zuo
* @date 2020/9/24 15:21
*/
public class AliPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用阿里支付...AliPayStrategy";
}
}
package com.ultiwill.strategy.impl;
import com.ultiwill.strategy.PayStrategy;
/**
* @author chong.zuo
* @date 2020/9/24 15:29
*/
public class WeChatPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用微信支付...WeChatPayStrategy";
}
}
package com.ultiwill.strategy.impl;
import com.ultiwill.strategy.PayStrategy;
/**
* @author chong.zuo
* @date 2020/9/24 15:34
*/
public class XiaomiPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用小米支付...XiaomiPayStrategy";
}
}
3. 枚举类定义映射地址
package com.ultiwill.strategy.enums;
import org.apache.commons.lang.StringUtils;
/**
* 枚举
* @author chong.zuo
* @date 2020/9/24 15:45
*/
public enum PayEnumStrategy {
/**
* 阿里支付
*/
ALI_PAY("1","com.ultiwill.strategy.impl.AliPayStrategy"),
/**
* 微信支付
*/
WECHAT_PAY("2","com.ultiwill.strategy.impl.WeChatPayStrategy"),
/**
* 小米支付
*/
XIAOMI_PAY("3","com.ultiwill.strategy.impl.XiaomiPayStrategy");
private String code;
private String className;
PayEnumStrategy() {
}
PayEnumStrategy(String code, String className) {
this.code = code;
this.className = className;
}
public static String getClassNameByCode(String code) {
String className = "";
if (StringUtils.isEmpty(code)) {
return className;
}
for (PayEnumStrategy e : PayEnumStrategy.values()) {
if (e.code.equalsIgnoreCase(code)) {
className = e.className;
break;
}
}
return className;
}
public String getCode() {
return code;
}
public String getClassName() {
return className;
}
}
4.工厂类反射执行
package com.ultiwill.strategy.factory;
import com.ultiwill.strategy.PayStrategy;
import com.ultiwill.strategy.enums.PayEnumStrategy;
/**
* @author chong.zuo
* @date 2020/9/24 16:10
*/
public class StrategyFactory {
/**
* 使用策略工厂获取具体策略实现
* @param code
* @return
*/
public static PayStrategy getPayStrategy(String code) {
try {
return (PayStrategy) Class.forName(PayEnumStrategy.getClassNameByCode(code)).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
5.上下文获取具体策略
package com.ultiwill.strategy.context;
import com.ultiwill.strategy.PayStrategy;
import com.ultiwill.strategy.enums.PayEnumStrategy;
import com.ultiwill.strategy.factory.StrategyFactory;
import org.apache.commons.lang.StringUtils;
/**
* 上下文
*
* @author chong.zuo
* @date 2020/9/24 15:41
*/
public class PayContextStrategy {
/**
* 获取具体的策略实现
*
* @param code
* @return
*/
public static String toPayHtml(String code) {
if (StringUtils.isBlank(code)) {
return "code不能为空...";
}
PayStrategy payStrategy = StrategyFactory.getPayStrategy(code);
if (payStrategy == null) {
return "没有找到具体的策略...";
}
return payStrategy.toPayHtml();
}
}
四、测试
controller:
package com.ultiwill.controller;
import com.ultiwill.strategy.context.PayContextStrategy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author c
* @date 2020/5/14 9:59
*/
@RestController
public class TestController {
@RequestMapping("/helloworld")
public String hello(String code) {
return PayContextStrategy.toPayHtml(code);
/*if ("0".equals(code)) {
return "调用阿里支付...AliPayStrategy";
} else if ("1".equals(code)) {
return "调用微信支付...AliPayStrategy";
} else if ("2".equals(code)) {
return "调用小米支付...AliPayStrategy";
}
return "调用接口不存在";
*/
}
}
pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ultiwill</groupId>
<artifactId>springboot-jar</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.8.RELEASE</version>
<configuration>
<includeSystemScope>true</includeSystemScope>
<mainClass>com.ultiwill.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
五、结果
六、在spring中通过Autowired注解实现策略模式
使用AutowireCapableBeanFactory手动注入
使用.newInstance();
创建对象的话,如果其他对象都使用Spring Autowired,还需要手动创建所有依赖的Bean:
private @Autowired AutowireCapableBeanFactory beanFactory;
public void process() {
MyBean obj = new MyBean();
beanFactory.autowireBean(obj);
// obj will now have its dependencies autowired.
}
本例中可以使用
private @Autowired AutowireCapableBeanFactory beanFactory;
/**
* 使用策略工厂获取具体策略实现
* @param code
* @return
*/
public PayStrategy getPayStrategy(String code) {
String className = PayEnumStrategy.getClassNameByCode(code);
try {
PayStrategy str = (PayStrategy) Class.forName(className).getDeclaredConstructor().newInstance();
beanFactory.autowireBean(str);
return str;
} catch (InstantiationException |
NoSuchMethodException |
ClassNotFoundException |
IllegalAccessException |
InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
使用Map<String,?> 自动注入
先附上如下的代码:
public interface TalkService {
void talk(String content);
}
@Service(value = "withSisterTalkService")
public class WithSisterTalkService implements TalkService {
@Override
public void talk(String content) {
System.out.println(this.getClass().getName() + ":" + content);
}
}
@Service(value = "withGirlFriendTalkService")
public class WithGirlFriendTalkService implements TalkService {
@Override
public void talk(String content) {
System.out.println(this.getClass().getName() + ":" + content);
}
}
@Service
public class TalkServiceStrategyContext implements TalkService {
private Map<String, TalkService> strategyMap = new ConcurrentHashMap<>();
@Autowired
public TalkServiceStrategyContext(Map<String, TalkService> strategyMap) {
this.strategyMap.clear();
this.strategyMap.putAll(strategyMap);
}
@Override
public void talk(String content) {
}
}
注意,这里必须是Map<String, TalkService>
类型!
@Autowired
private Map<String, TalkService> talkServiceMap;
@GetMapping(value = "doTest")
public String doTest() {
Set<String> strings = talkServiceMap.keySet();
for (String string : strings) {
System.out.println(string + ":" + talkServiceMap.get(string).toString());
}
return this.getClass().getName();
}
其访问测试controller后,打印的信息如下:
talkServiceStrategyContext:com.haiyang.onlinejava.complier.service.impl.TalkServiceStrategyContext@2f0b1419
withGirlFriendTalkService:com.haiyang.onlinejava.complier.service.impl.WithGirlFriendTalkService@1cf19a02
withSisterTalkService:com.haiyang.onlinejava.complier.service.impl.WithSisterTalkService@1ef3c76d
看了后感觉很奇怪,在上方只定义了一个map<String,TalkService>的map,居然它就能自动找到实现了TalkService的所有bean,并将service的beanName作为了key,感觉还是牛逼啊,spring的注解居然还能这样用。
然后简单看了下Autowired的源码,其javaDoc文档里也有说明:
package org.springframework.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks a constructor, field, setter method or config method as to be
* autowired by Spring's dependency injection facilities.
*
* <p>Only one constructor (at max) of any given bean class may carry this
* annotation, indicating the constructor to autowire when used as a Spring
* bean. Such a constructor does not have to be public.
*
* <p>Fields are injected right after construction of a bean, before any
* config methods are invoked. Such a config field does not have to be public.
*
* <p>Config methods may have an arbitrary name and any number of arguments;
* each of those arguments will be autowired with a matching bean in the
* Spring container. Bean property setter methods are effectively just
* a special case of such a general config method. Such config methods
* do not have to be public.
*
* <p>In the case of multiple argument methods, the 'required' parameter is
* applicable for all arguments.
*
* <p>In case of a {@link java.util.Collection} or {@link java.util.Map}
* dependency type, the container will autowire all beans matching the
* declared value type. In case of a Map, the keys must be declared as
* type String and will be resolved to the corresponding bean names.
*
* <p>Note that actual injection is performed through a
* {@link org.springframework.beans.factory.config.BeanPostProcessor
* BeanPostProcessor} which in turn means that you <em>cannot</em>
* use {@code @Autowired} to inject references into
* {@link org.springframework.beans.factory.config.BeanPostProcessor
* BeanPostProcessor} or
* {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor}
* types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
* class (which, by default, checks for the presence of this annotation).
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 2.5
* @see AutowiredAnnotationBeanPostProcessor
* @see Qualifier
* @see Value
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
关注这句:
In case of a java.util.Collection or java.util.Map dependency type, the container will autowire all beans matching the declared value type. In case of a Map, the keys must be declared as type String and will be resolved to the corresponding bean names.
它大致是说Autowired当使用在Collection里时,会将所申明类的所有实现类都放在那个指定的Collection里;
如果Autowired和map使用的话呢,它将它bean的名称作为key,所有的bean作为value.
使用Set<?>自动注入
如果不想使用bean的名字作为map的Key的话,我们可以自定义寻址方式,自动注入时候使用Set<?>:
public interface Strategy {
void doStuff();
StrategyName getStrategyName();
}
public enum StrategyName {
StrategyA,
StrategyB,
StrategyC
}
@Component
public class StrategyA implements Strategy{
@Override
public void doStuff() {
//implement algorithm A here
}
@Override
public StrategyName getStrategyName() {
return StrategyName.StrategyA;
}
}
@Component
public class StrategyB implements Strategy{
@Override
public void doStuff() {
//implement algorithm B here
}
@Override
public StrategyName getStrategyName() {
return StrategyName.StrategyB;
}
}
@Component
public class StrategyC implements Strategy{
@Override
public void doStuff() {
}
@Override
public StrategyName getStrategyName() {
return StrategyName.StrategyC;
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.stereotype.Component;
@Component
public class StrategyFactory {
private Map<StrategyName, Strategy> strategies;
@Autowired
public StrategyFactory(Set<Strategy> strategySet) {
createStrategy(strategySet);
}
public Strategy findStrategy(StrategyName strategyName) {
return strategies.get(strategyName);
}
private void createStrategy(Set<Strategy> strategySet) {
strategies = new HashMap<StrategyName, Strategy>();
strategySet.forEach(
strategy ->strategies.put(strategy.getStrategyName(), strategy));
}
}
Now we can inject StrategyFactory using @Autowired annotation. Here is the sample code using our StrategyFactory.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SomeService {
@Autowired
private StrategyFactory strategyFactory;
public void findSome(){
// Now get the strategy by passing the name
Strategy strategy = strategyFactory.findStrategy(StrategyName.StrategyA);
// you can now call the methods defined in strategy.
strategy.doStuff();
}
}
Java 设计模式--策略模式,枚举+工厂方法实现的更多相关文章
-
Java设计模式(二) 工厂方法模式
本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...
-
我的Java设计模式-策略模式
今天给大家说说田忌赛马的故事.如有雷同,纯属巧合!话说在战国时期,群雄割据,硝烟四起,茶余饭后还是少不了娱乐活动的,其中赛马是最火爆的.一天,孙膑看到田忌像个死鸡似的就知道肯定赛马又输给了齐威王,立马 ...
-
Java设计模式学习笔记(三) 工厂方法模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...
-
Java设计模式:Factory Method(工厂方法)模式
概念定义 工厂方法(Factory Method)模式,又称多态工厂(Polymorphic Factory)模式或虚拟构造器(Virtual Constructor)模式.工厂方法模式通过定义工厂抽 ...
-
JAVA设计模式——第 5 章 工厂方法模式【Factory Method Pattern】(转)
女娲补天的故事大家都听说过吧,今天不说这个,说女娲创造人的故事,可不是“造人”的工作,这个词被现代人滥用了.这个故事是说,女娲在补了天后,下到凡间一看,哇塞,风景太优美了,天空是湛蓝的,水是清澈的,空 ...
-
Java设计模式(四)工厂方法模式
定义与类型 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行. 类型:创建型 适用场景 创建对象需要大量重复的代码 客户端(应用层)不依赖于产 ...
-
Java设计模式菜鸟系列(四)工厂方法模式建模与实现
转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39760895 工厂方法模式(Factory Method) 工厂方法:顾名思义,就是调用工 ...
-
Java设计模式—策略模式
1.策略模式(Strategy Pattern)是一种比较简单的模式,也叫做政策模式(PolicyPattern). 定义如下: Define a family of algorithms,e ...
-
java设计模式 策略模式Strategy
本章讲述java设计模式中,策略模式相关的知识点. 1.策略模式定义 策略模式,又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户.策略模式属于对象的 ...
随机推荐
-
Android的init过程(二):初始化语言(init.rc)解析【转】
转自:http://www.cnblogs.com/nokiaguy/p/3164799.html Android的init过程(一) 本文使用的软件版本 Android:4.2.2 Linux内核: ...
-
NSDateFormatter 格式说明
格式化参数如下: G: 公元时代,例如AD公元 yy: 年的后2位 yyyy: 完整年 MM: 月,显示为1-12 MMM: 月,显示为英文月份简写,如 Jan M ...
-
OpenStack Keystone v3 API新特性
原连接 http://blog.chinaunix.net/uid-21335514-id-3497996.html keystone的v3 API与v2.0相比有很大的不同,从API的请求格式到re ...
-
Web API Test Client 1.2.0
使用方法 1 安装 matthewcv.WebApiTestClient 到你的Web API 项目 PM> Install-Package matthewcv.WebApiTestClient ...
-
点击空白处隐藏指定dom元素(纯javascript方法)
<script type="text/javascript"> document.onclick = function (event) { event = event ...
-
mysql主键约束和唯一性约束
主键约束和唯一性约束都是索引,它们的区别是: 主键字段可以确保唯一性,但主键字段不能为NULL. 唯一性约束可以确保唯一性,但唯一性约束的字段可以为NULL 唯一性约束对含有NULL的记录不起作用,即 ...
-
RHEL7.2安装
先在系统启动的时候按下Del键(有些系统是F2键)进入BIOS,设置从光盘启动. 系统只有2个USB口时,1个要接光驱,另外1个口不能同时接键盘和鼠标,可以接1个USB集线器,键盘和鼠标同时接入到集线 ...
-
Django学习之六:Django 常用模块导入记忆
Django 常用模块导入记忆 django相关 1. urls相关操作 from django.urls import path, re_path, include from django.urls ...
-
odoo 学习
1.2.3.41.2.5.62.410.6变成1.234,1.256,2.4,10.6 def get_bom_namenum(self, cr, uid, ids, field_name, arg, ...
-
ajax 执行代码顺序
异步:ajax执行过程中,ajax后面的代码也执行了,程序没按顺序走 同步:ajax执行完毕后再执行后面的代码,程序顺序执行 在jq中ajax默认是异步的 当设置async:false表示的就是同步的 ...