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());
    }
}
相关推荐
程序员契奇18 分钟前
Tools工具使用
人工智能·后端
IT_陈寒35 分钟前
SpringBoot自动配置没生效?你可能漏了这个注解
前端·人工智能·后端
长明39 分钟前
C#项目组织与概念梳理
后端·c#
xn71331 小时前
个人网站站外分发怎么做归因?我给 XBSTACK 补了一套 UTM 追踪规则
后端·低代码
用户2330713074791 小时前
JUC 并发容器与工具
后端
冰暮流星1 小时前
flask之模版渲染
后端·python·flask
威武的花瓣1 小时前
细说ASP.NET的各种异步操作
后端·asp.net·php
漂亮的摩托1 小时前
如何编写一个SpringBoot项目告警推送的Starter
java·spring boot·后端
任性的芝麻1 小时前
ASP.NET MVC 中的异步方式
后端·asp.net·mvc
雨师@1 小时前
go语言项目--实例化(图书管理)--006
开发语言·后端·golang