广州网站排名怎么优化,中华衣柜网,自适应网站dedecms代码,企业标志设计图片1. 概述
先看下面的图片#xff0c;我们去旅游选择出行模式有很多种#xff0c;可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。 作为一个程序猿#xff0c;开发需要选择一款开发工具#xff0c;当然可以进行代码开发的工具有很多#xff0c;可以选择Idea进行开发我们去旅游选择出行模式有很多种可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。 作为一个程序猿开发需要选择一款开发工具当然可以进行代码开发的工具有很多可以选择Idea进行开发也可以使用eclipse进行开发也可以使用其他的一些开发工具。 定义
该模式定义了一系列算法并将每个算法封装起来使它们可以相互替换且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式它通过对算法进行封装把使用算法的责任和算法的实现分割开来并委派给不同的对象对这些算法进行管理。
2. 结构
策略模式的主要角色如下
抽象策略Strategy类这是一个抽象角色通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。具体策略Concrete Strategy类实现了抽象策略定义的接口提供具体的算法实现或行为。环境Context类持有一个策略类的引用最终给客户端调用。
3. 案例实现
【例】促销活动
一家百货公司在定年度的促销活动。针对不同的节日春节、中秋节、圣诞节推出不同的促销活动由促销员将促销活动展示给客户。类图如下 聚合关系可以用带空心菱形的实线来表示。 代码如下
定义百货公司所有促销活动的共同接口。
public interface Strategy {void show();
}定义具体策略角色Concrete Strategy每个节日具体的促销活动。
//为春节准备的促销活动A
public class StrategyA implements Strategy {public void show() {System.out.println(买一送一);}
}//为中秋准备的促销活动B
public class StrategyB implements Strategy {public void show() {System.out.println(满200元减50元);}
}//为圣诞准备的促销活动C
public class StrategyC implements Strategy {public void show() {System.out.println(满1000元加一元换购任意200元以下商品);}
}定义环境角色Context用于连接上下文即把促销活动推销给客户这里可以理解为销售员。
public class SalesMan { //持有抽象策略角色的引用 private Strategy strategy; public SalesMan(Strategy strategy) { this.strategy strategy; } //向客户展示促销活动 public void salesManShow(){ strategy.show(); }
} 4. 综合案例
4.1 概述
下图是gitee的登录的入口其中有多种方式可以进行登录。 用户名密码登录 短信验证码登录 微信登录 QQ登录 … 4.2 目前已实现的代码
(1)登录接口
说明请求方式POST路径/api/user/login参数LoginReq返回值LoginResp
请求参数LoginReq
Data
public class LoginReq {private String name;private String password;private String phone;private String validateCode;//手机验证码private String wxCode;//用于微信登录/*** account : 用户名密码登录* sms : 手机验证码登录* we_chat : 微信登录*/private String type;
}响应参数LoginResp
Data
public class LoginResp{private Integer userId;private String userName;private String roleCode;private String token; //jwt令牌private boolean success;}控制层LoginController
RestController
RequestMapping(/api/user)
public class LoginController {Autowiredprivate UserService userService;PostMapping(/login)public LoginResp login(RequestBody LoginReq loginReq){return userService.login(loginReq);}
}业务层UserService
Service
public class UserService {public LoginResp login(LoginReq loginReq){if(loginReq.getType().equals(account)){System.out.println(用户名密码登录);//执行用户密码登录逻辑return new LoginResp();}else if(loginReq.getType().equals(sms)){System.out.println(手机号验证码登录);//执行手机号验证码登录逻辑return new LoginResp();}else if (loginReq.getType().equals(we_chat)){System.out.println(微信登录);//执行用户微信登录逻辑return new LoginResp();}LoginResp loginResp new LoginResp();loginResp.setSuccess(false);System.out.println(登录失败);return loginResp;}
}注意我们重点讲的是设计模式并不是登录的逻辑所以以上代码并没有真正的实现登录功能。 (2)问题分析
业务层代码大量使用到了if...else在后期阅读代码的时候会非常不友好大量使用if...else性能也不高。如果业务发生变更比如现在新增了QQ登录方式这个时候需要修改业务层代码违反了开闭原则。
解决
使用工厂方法设计模式策略模式解决。
4.3 代码改造工厂策略
1整体思路
改造之后不在service中写业务逻辑让service调用工厂然后通过service传递不同的参数来获取不同的登录策略登录方式。 2具体实现
抽象策略类UserGranter
/*** 抽象策略类*/
public interface UserGranter{/*** 获取数据* param loginReq 传入的参数* return map值*/LoginResp login(LoginReq loginReq);
}具体的策略AccountGranter、SmsGranter、WeChatGranter
/*** 策略账号登录**/
Component
public class AccountGranter implements UserGranter{Overridepublic LoginResp login(LoginReq loginReq) {System.out.println(登录方式为账号登录 loginReq);// TODO// 执行业务操作 return new LoginResp();}
}
/*** 策略:短信登录*/
Component
public class SmsGranter implements UserGranter{Overridepublic LoginResp login(LoginReq loginReq) {System.out.println(登录方式为短信登录 loginReq);// TODO// 执行业务操作return new LoginResp();}
}
/*** 策略:微信登录*/
Component
public class WeChatGranter implements UserGranter{Overridepublic LoginResp login(LoginReq loginReq) {System.out.println(登录方式为微信登录 loginReq);// TODO// 执行业务操作return new LoginResp();}
}工程类UserLoginFactory
/*** 操作策略的上下文环境类 工具类* 将策略整合起来 方便管理*/
Component
public class UserLoginFactory implements ApplicationContextAware {private static MapString, UserGranter granterPool new ConcurrentHashMap();Autowiredprivate LoginTypeConfig loginTypeConfig;/*** 从配置文件中读取策略信息存储到map中* {* account:accountGranter,* sms:smsGranter,* we_chat:weChatGranter* }** param applicationContext* throws BeansException*/Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {loginTypeConfig.getTypes().forEach((k, y) - {granterPool.put(k, (UserGranter) applicationContext.getBean(y));});}/*** 对外提供获取具体策略** param grantType 用户的登录方式需要跟配置文件中匹配* return 具体策略*/public UserGranter getGranter(String grantType) {UserGranter tokenGranter granterPool.get(grantType);return tokenGranter;}}在application.yml文件中新增自定义配置
login:types:account: accountGrantersms: smsGranterwe_chat: weChatGranter新增读取数据配置类
Getter
Setter
Configuration
ConfigurationProperties(prefix login)
public class LoginTypeConfig {private MapString,String types;}
改造service代码
Service
public class UserService {Autowiredprivate UserLoginFactory factory;public LoginResp login(LoginReq loginReq){UserGranter granter factory.getGranter(loginReq.getType());if(granter null){LoginResp loginResp new LoginResp();loginResp.setSuccess(false);return loginResp;}LoginResp loginResp granter.login(loginReq);return loginResp;}
}大家可以看到我们使用了设计模式之后业务层的代码就清爽多了如果后期有新的需求改动比如加入了QQ登录我们只需要添加对应的策略就可以无需再改动业务层代码。
4.4 举一反三
其实像这样的需求在日常开发中非常常见场景有很多以下的情景都可以使用工厂模式策略模式解决。比如
订单的支付策略 支付宝支付微信支付银行卡支付现金支付 解析不同类型excel xls格式xlsx格式 打折促销 满300元9折满500元8折满1000元7折 物流运费阶梯计算 5kg以下5kg-10kg10kg-20kg20kg以上
一句话总结只要代码中有冗长的if-else或switch分支判断都可以采用策略模式优化。