Java设计模式

工厂模式

案例

现在有一家咖啡店,用户选择两种咖啡:美式咖啡和拿铁咖啡

原代码

定义 coffee 类通用接口

csharp 复制代码
public interface Coffee {
    public String getName();
    public void addMilk();
    public void addSugar();
}

子类 AmericanCoffee 相关操作

typescript 复制代码
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 相关操作

typescript 复制代码
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");
    }
}

用户点咖啡

typescript 复制代码
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 接口

csharp 复制代码
public interface Coffee {
    public String getName();
    public void addMilk();
    public void addSugar();
}

子类 AmericanCoffee 实现类

typescript 复制代码
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 实现类

typescript 复制代码
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");
    }
}

咖啡工厂类

typescript 复制代码
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;
    }

}

用户点咖啡

typescript 复制代码
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());
    }

}

小结

  • 所有的产品共有一个工厂,如果新增产品,则需要修改代码,违反开闭原则
  • 是一种编程思想,可以借鉴这种编程思路

工厂方法模式

咖啡操作接口

csharp 复制代码
public interface Coffee {
    public String getName();
    public void addMilk();
    public void addSugar();
}

子类AmericanCoffee 实现类

typescript 复制代码
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实现类

typescript 复制代码
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");
    }
}

通用咖啡种类工厂

csharp 复制代码
public interface CoffeeFactory {
    public Coffee createCoffee();
}

子类 AmericanCoffeeFactory 工厂

typescript 复制代码
public class AmericanCoffeeFactory implements CoffeeFactory{
    @Override
    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}

子类 LatterCoffeeFactory工厂

typescript 复制代码
public class LatterCoffeeFactory implements CoffeeFactory{
    @Override
    public Coffee createCoffee() {
        return new LatterCoffee();
    }
}

用户点咖啡

ini 复制代码
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判断)
  • 它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理

案例

用户旅游出行,可以选择自行车、汽车、火车或者飞机出行方式

代码

定义出行策略接口

csharp 复制代码
public interface TravelStrategy {
    // 出行方式
    public void travel();

}

子类Aircraft

typescript 复制代码
public class Aircraft implements TravelStrategy {


    @Override
    public void travel() {
        System.out.println("选择飞机出行");
    }
}

子类Bicycle

typescript 复制代码
public class Bicycle implements  TravelStrategy{

    @Override
    public void travel() {
        System.out.println("选择自行车出行");
    }
}

子类Car

typescript 复制代码
public class Car implements TravelStrategy{
    @Override
    public void travel() {
        System.out.println("选择汽车出行");
    }
}

出行操作类

typescript 复制代码
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...

案例(工厂 + 策略)

用户登录可以选择方式:账号密码、短信登录、微信登录...

原代码

登录方式实体类

typescript 复制代码
@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

less 复制代码
@RequestMapping("/api/user")
@RestController
public class LoginController {
    @Autowired
    private UserService userService;

    @RequestMapping("login")
    public LoginResp login(@RequestBody LoginReq loginReq){
        return userService.login(loginReq);
    }

}

登录操作实现类

csharp 复制代码
@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;
    }
}

修改后代码

新增通用登录接口

csharp 复制代码
public interface UserGranter {
    LoginResp login(LoginReq loginReq);
}

账号登录实现类

typescript 复制代码
@Component
public class AccountGranter implements UserGranter{

    @Override
    public LoginResp login(LoginReq loginResp) {
        System.out.println("账号登录");

        return new LoginResp();
    }
}

手机登录实现类

typescript 复制代码
@Component
public class SmsGranter implements UserGranter{

    @Override
    public LoginResp login(LoginReq loginResp) {
        System.out.println("手机登录");

        return new LoginResp();
    }
}

微信登录实现类

typescript 复制代码
@Component
public class WeChatGranter implements UserGranter{
    @Override
    public LoginResp login(LoginReq loginResp) {
        System.out.println("微信登录");

        return new LoginResp();
    }
}

application.yml配置登录方式以及实现类

yaml 复制代码
login:
  types:
      account: accountGranter
      sms: smsGranter
      we_chat: weChatGranter
typescript 复制代码
@Component
public class UserLoginFactory implements ApplicationContextAware {
    
    // 存储yml文件中"登录方式"和"实现类"信息
    @Autowired
    private LoginTypeConfig loginTypeConfig;
    
     // 翻译loginTypeConfig,将String类型的实现类转换为具体实现Bean
    private static Map<String,UserGranter> 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

java 复制代码
@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...

责任链模式

定义

为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止

案例

订单处理: 校验参数 -> 填充订单数据 -> 算价 -> 落库

代码

创建订单实体类

typescript 复制代码
@Data
public class OrderInfo {

    private String productId;
    private String userId;
    private BigDecimal amount;

}

创建处理接口

java 复制代码
@Setter
public abstract class Handler {

     Handler handler;
     /*
     * 处理过程
     * */
    public abstract void process(OrderInfo orderInfo);
    
}

订单入库操作

scala 复制代码
public class OrderCreat extends Handler{
    @Override
    public void process(OrderInfo orderInfo) {
        System.out.println("订单入库");
    }
}

补充订单操作

scala 复制代码
public class OrderFill  extends Handler{
    @Override
    public void process(OrderInfo orderInfo) {
        System.out.println("补充订单信息");
        handler.process(orderInfo);
    }
}

校验订单信息操作

scala 复制代码
public class OrderValidition extends Handler{
    @Override
    public void process(OrderInfo orderInfo) {
        System.out.println("校验订单信息");
        handler.process(orderInfo);
    }
}

计算金额-优惠操作

scala 复制代码
public class OrderAmountCalculate extends Handler{
    @Override
    public void process(OrderInfo orderInfo) {
        System.out.println("计算金额-优惠卷");
        handler.process(orderInfo);
    }
}

处理责任链

java 复制代码
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());
    }
}
相关推荐
招风的黑耳2 分钟前
智慧养老项目:当SpringBoot遇到硬件,如何优雅地处理异常与状态管理?
java·spring boot·后端
回家路上绕了弯8 分钟前
分布式锁原理深度解析:从理论到实践
分布式·后端
磊磊磊磊磊24 分钟前
用AI做了个排版工具,分享一下如何高效省钱地用AI!
前端·后端·react.js
hgz071032 分钟前
Spring Boot Starter机制
java·spring boot·后端
daxiang1209220533 分钟前
Spring boot服务启动报错 java.lang.StackOverflowError 原因分析
java·spring boot·后端
我家领养了个白胖胖34 分钟前
极简集成大模型!Spring AI Alibaba ChatClient 快速上手指南
java·后端·ai编程
一代明君Kevin学长1 小时前
快速自定义一个带进度监控的文件资源类
java·前端·后端·python·文件上传·文件服务·文件流
aiopencode1 小时前
上架 iOS 应用到底在做什么?从准备工作到上架的流程
后端
哈哈老师啊2 小时前
Springboot简单二手车网站qs5ed(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
JIngJaneIL2 小时前
基于Java+ vue图书管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端