工厂模式
案例
现在有一家咖啡店,用户选择两种咖啡:美式咖啡和拿铁咖啡
原代码
定义 coffee 类通用接口
public interface Coffee {
public String getName();
public void addMilk();
public void addSugar();
}
子类 AmericanCoffee 相关操作
public class AmericanCoffee implements Coffee {
@Override
public String getName() {
return "AmericanCoffee";
}
@Override
public void addMilk() {
System.out.println("AmericanCoffee addMilk");
}
@Override
public void addSugar() {
System.out.println("AmericanCoffee addSugar");
}
}
子类 LatterCoffee 相关操作
public class LatterCoffee implements Coffee{
@Override
public String getName() {
return "LatterCoffee";
}
@Override
public void addMilk() {
System.out.println("LatterCoffee addMilk");
}
@Override
public void addSugar() {
System.out.println("LatterCoffee addSugar");
}
}
用户点咖啡
public class CoffeeStore {
public static Coffee orderCoffee(String type){
Coffee coffee = null;
if("american".equals(type)){
coffee = new AmericanCoffee();
}else {
coffee = new LatterCoffee();
}
// 添加配料
coffee.addMilk();
coffee.addSugar();
return coffee;
}
public static void main(String[] args) {
Coffee coffee = orderCoffee("latter");
System.out.println(coffee.getName());
}
}
简单工厂模式
通用 coffee 接口
public interface Coffee {
public String getName();
public void addMilk();
public void addSugar();
}
子类 AmericanCoffee 实现类
public class AmericanCoffee implements Coffee {
@Override
public String getName() {
return "AmericanCoffee";
}
@Override
public void addMilk() {
System.out.println("AmericanCoffee addMilk");
}
@Override
public void addSugar() {
System.out.println("AmericanCoffee addSugar");
}
}
子类 LatterCoffee 实现类
public class LatterCoffee implements Coffee {
@Override
public String getName() {
return "LatterCoffee";
}
@Override
public void addMilk() {
System.out.println("LatterCoffee addMilk");
}
@Override
public void addSugar() {
System.out.println("LatterCoffee addSugar");
}
}
咖啡工厂类
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type){
Coffee coffee = null;
if("american".equals(type)){
coffee = new AmericanCoffee();
}else {
coffee = new LatterCoffee();
}
return coffee;
}
}
用户点咖啡
public class CoffeeStore {
public static Coffee orderCoffee(String type){
Coffee coffee = SimpleCoffeeFactory.createCoffee(type);
// 添加配料
coffee.addMilk();
coffee.addSugar();
return coffee;
}
public static void main(String[] args) {
Coffee coffee = orderCoffee("latter");
System.out.println(coffee.getName());
}
}
小结
- 所有的产品共有一个工厂,如果新增产品,则需要修改代码,违反开闭原则
- 是一种编程思想,可以借鉴这种编程思路
工厂方法模式
咖啡操作接口
public interface Coffee {
public String getName();
public void addMilk();
public void addSugar();
}
子类AmericanCoffee 实现类
public class AmericanCoffee implements Coffee {
@Override
public String getName() {
return "AmericanCoffee";
}
@Override
public void addMilk() {
System.out.println("AmericanCoffee addMilk");
}
@Override
public void addSugar() {
System.out.println("AmericanCoffee addSugar");
}
}
子类LatterCoffee实现类
public class LatterCoffee implements Coffee {
@Override
public String getName() {
return "LatterCoffee";
}
@Override
public void addMilk() {
System.out.println("LatterCoffee addMilk");
}
@Override
public void addSugar() {
System.out.println("LatterCoffee addSugar");
}
}
通用咖啡种类工厂
public interface CoffeeFactory {
public Coffee createCoffee();
}
子类 AmericanCoffeeFactory 工厂
public class AmericanCoffeeFactory implements CoffeeFactory{
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
子类 LatterCoffeeFactory工厂
public class LatterCoffeeFactory implements CoffeeFactory{
@Override
public Coffee createCoffee() {
return new LatterCoffee();
}
}
用户点咖啡
public class CoffeeStore {
private CoffeeFactory coffeeFactory;
public CoffeeStore(CoffeeFactory coffeeFactory){
this.coffeeFactory = coffeeFactory;
}
public Coffee orderCoffee(){
Coffee coffee = coffeeFactory.createCoffee();
// 添加配料
coffee.addMilk();
coffee.addSugar();
return coffee;
}
public static void main(String[] args) {
CoffeeStore coffeeStore = new CoffeeStore(new LatterCoffeeFactory());
Coffee coffee = coffeeStore.orderCoffee();
System.out.println(coffee.getName());
}
}
小结
优点:
-
用户只需知道工厂名称就可以得到新的产品,无需知道产品具体的创造过程
-
在系统增加新的产品时只需添加具体产品类和对应的具体工厂类,无需对工厂进行任何修改,满足开闭原则
缺点:
- 每增加一个产品就要增加一个具体的产品类和对应的具体工厂类,这增加了系统的复杂度
策略模式
定义
- 该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户(可以看作if-else判断)
- 它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理
案例
用户旅游出行,可以选择自行车、汽车、火车或者飞机出行方式
代码
定义出行策略接口
public interface TravelStrategy {
// 出行方式
public void travel();
}
子类Aircraft
public class Aircraft implements TravelStrategy {
@Override
public void travel() {
System.out.println("选择飞机出行");
}
}
子类Bicycle
public class Bicycle implements TravelStrategy{
@Override
public void travel() {
System.out.println("选择自行车出行");
}
}
子类Car
public class Car implements TravelStrategy{
@Override
public void travel() {
System.out.println("选择汽车出行");
}
}
出行操作类
public class TravelContext {
// 出行方式
private TravelStrategy travelStrategy;
// 根据出行方式构建对应实体类
public TravelContext(TravelStrategy travelStrategy){
this.travelStrategy = travelStrategy;
}
// 根据出行方式选择出行操作
public void selectTravel(){
this.travelStrategy.travel();
}
// 测试
public static void main(String[] args) {
TravelContext travelContext = new TravelContext(new Aircraft());
travelContext.selectTravel();
}
}
小结
优点:
- 策略类之间可以自由切换
- 易于扩展
- 避免使用多重条件选择语句(if else),充分体现面向对象设计思想
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
- 策略模式将造成产生很多策略类
代码地址: gitee.com/gitee-enter…
案例(工厂 + 策略)
用户登录可以选择方式:账号密码、短信登录、微信登录...
原代码
登录方式实体类
@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;
}
LoginController
@RequestMapping("/api/user")
@RestController
public class LoginController {
@Autowired
private UserService userService;
@RequestMapping("login")
public LoginResp login(@RequestBody LoginReq loginReq){
return userService.login(loginReq);
}
}
登录操作实现类
@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;
}
}
修改后代码
新增通用登录接口
public interface UserGranter {
LoginResp login(LoginReq loginReq);
}
账号登录实现类
@Component
public class AccountGranter implements UserGranter{
@Override
public LoginResp login(LoginReq loginResp) {
System.out.println("账号登录");
return new LoginResp();
}
}
手机登录实现类
@Component
public class SmsGranter implements UserGranter{
@Override
public LoginResp login(LoginReq loginResp) {
System.out.println("手机登录");
return new LoginResp();
}
}
微信登录实现类
@Component
public class WeChatGranter implements UserGranter{
@Override
public LoginResp login(LoginReq loginResp) {
System.out.println("微信登录");
return new LoginResp();
}
}
application.yml配置登录方式
以及实现类
login:
types:
account: accountGranter
sms: smsGranter
we_chat: weChatGranter
@Component
public class UserLoginFactory implements ApplicationContextAware {
// 存储yml文件中"登录方式"和“实现类”信息
@Autowired
private LoginTypeConfig loginTypeConfig;
// 翻译loginTypeConfig,将String类型的实现类转换为具体实现Bean
private static Map granterPool = new ConcurrentHashMap();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
loginTypeConfig.getTypes().forEach(( k,v)->{
granterPool.put(String.valueOf(k),(UserGranter) applicationContext.getBean(v));
});
}
public UserGranter getGranter(String grantType){
UserGranter userGranter = granterPool.get(grantType);
return userGranter;
}
}
修改后的Service
@Service
public class UserService {
@Autowired
private 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);
loginResp.setSuccess(true);
return loginResp;
}
}
代码地址 : gitee.com/gitee-enter…
责任链模式
定义
为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止
案例
订单处理: 校验参数 -> 填充订单数据 -> 算价 -> 落库
代码
创建订单实体类
@Data
public class OrderInfo {
private String productId;
private String userId;
private BigDecimal amount;
}
创建处理接口
@Setter
public abstract class Handler {
Handler handler;
/*
* 处理过程
* */
public abstract void process(OrderInfo orderInfo);
}
订单入库操作
public class OrderCreat extends Handler{
@Override
public void process(OrderInfo orderInfo) {
System.out.println("订单入库");
}
}
补充订单操作
public class OrderFill extends Handler{
@Override
public void process(OrderInfo orderInfo) {
System.out.println("补充订单信息");
handler.process(orderInfo);
}
}
校验订单信息操作
public class OrderValidition extends Handler{
@Override
public void process(OrderInfo orderInfo) {
System.out.println("校验订单信息");
handler.process(orderInfo);
}
}
计算金额-优惠操作
public class OrderAmountCalculate extends Handler{
@Override
public void process(OrderInfo orderInfo) {
System.out.println("计算金额-优惠卷");
handler.process(orderInfo);
}
}
处理责任链
public class Application {
public static void main(String[] args) {
// 校验订单
OrderValidition orderValidition = new OrderValidition();
// 补充订单信息
OrderFill orderFill = new OrderFill();
//订单算价
OrderAmountCalculate orderAmountCalculate = new OrderAmountCalculate();
// 订单落库
OrderCreat orderCreat = new OrderCreat();
// 设置责任链路
orderValidition.setHandler(orderFill);
orderFill.setHandler(orderAmountCalculate);
orderAmountCalculate.setHandler(orderCreat);
//开始执行
orderValidition.process(new OrderInfo());
}
}