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());
    }
}
相关推荐
Amagi.1 小时前
Spring中Bean的作用域
java·后端·spring
2402_857589361 小时前
Spring Boot新闻推荐系统设计与实现
java·spring boot·后端
J老熊2 小时前
Spring Cloud Netflix Eureka 注册中心讲解和案例示范
java·后端·spring·spring cloud·面试·eureka·系统架构
Benaso2 小时前
Rust 快速入门(一)
开发语言·后端·rust
sco52822 小时前
SpringBoot 集成 Ehcache 实现本地缓存
java·spring boot·后端
原机小子2 小时前
在线教育的未来:SpringBoot技术实现
java·spring boot·后端
吾日三省吾码2 小时前
详解JVM类加载机制
后端
努力的布布2 小时前
SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器
java·后端·spring
PacosonSWJTU3 小时前
spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)
java·后端·springmvc
记得开心一点嘛3 小时前
在Java项目中如何使用Scala实现尾递归优化来解决爆栈问题
开发语言·后端·scala