• 设计模式原则——里氏替换原则


    设计模式原则

    设计模式示例代码库地址:

    https://gitee.com/Jasonpupil/designPatterns

    里氏替换原则

    • 继承必须确保父类所拥有的性质在子类中依然成立

    • 开闭原则不同的是开闭原则可以改变父类原有的功能,里氏替换原则不能修改父类的原有的性质,即使子类扩展了父类的功能,也不能改变父类的原有功能

    • 提高兼容性、维护性和扩展性

      • 子类和父类的接口保持一致,确保在任何使用父类的地方都可以替换为子类,而不会影响系统功能
      • 子类能够无缝地替换父类,替换时不需要修改客户端代码,方便地扩展新功能而不需要对现有代码进行大规模修改
      • 由于子类完全遵循父类的契约,系统在替换子类时不容易出现未预见的运行时错误

    使用场景:银行卡存储,

    • 信用卡继承并重写储蓄卡的功能,破坏了里氏替换原则,根据里氏替换原则进行修改

    里氏替换原则替换前示例代码:

    储蓄卡类:
    /**
     * @Description: 模拟储蓄卡功能
     * @Author: pupil
     * @Date: 2024/06/23 下午 10:04
     */
    public class CashCard {
    
        private Logger logger = LoggerFactory.getLogger(CashCard.class);
    
        private static List<String> tradeList = new ArrayList<>();
    
        /**
         * 提现
         *
         * @param orderId 单号
         * @param amount  金额
         * @return 状态码 0000成功、0001失败、0002重复
         */
        public String withdrawal(String orderId, BigDecimal amount) {
            // 模拟支付成功
            logger.info("提现成功,单号:{} 金额:{}", orderId, amount);
            return "0000";
        }
    
        /**
         * 储蓄
         *
         * @param orderId 单号
         * @param amount  金额
         * @return 状态码 0000成功、0001失败、0002重复
         */
        public String recharge(String orderId, BigDecimal amount) {
            // 模拟充值成功
            logger.info("储蓄成功,单号:{} 金额:{}", orderId, amount);
            return "0000";
        }
    
        /**
         * 交易流水查询
         *
         * @return 交易流水
         */
        public List<String> tradeFlow() {
            logger.info("交易流水查询成功");
            tradeList.add("14451,100.00");
            tradeList.add("14451,65.00");
            tradeList.add("14451,76.50");
            tradeList.add("14451,126.00");
            return tradeList;
        }
    }
    
    信用卡类:
     /**
       * @Description: 模拟信用卡功能,重写父类的方法,违法里氏替换原则
       * @Author: pupil
       * @Date: 2024/06/23 下午 10:32
       */
      public class CreditCard extends CashCard{
      
          private Logger logger = LoggerFactory.getLogger(CashCard.class);
      
          /**
           * @param orderId 单号
           * @param amount  金额
           * @return 状态码 0000成功、0001失败、0002重复
           */
          @Override
          public String withdrawal(String orderId, BigDecimal amount) {
              // 校验
              if (amount.compareTo(new BigDecimal(1000)) >= 0){
                  logger.info("贷款金额校验(限额1000元),单号:{} 金额:{}", orderId, amount);
                  return "0001";
              }
              // 模拟生成贷款单
              logger.info("生成贷款单,单号:{} 金额:{}", orderId, amount);
              // 模拟支付成功
              logger.info("贷款成功,单号:{} 金额:{}", orderId, amount);
              return "0000";
          }
      
          /**
           *
           * @param orderId 单号
           * @param amount  金额
           * @return 状态码 0000成功、0001失败、0002重复
           */
          @Override
          public String recharge(String orderId, BigDecimal amount) {
              // 模拟生成还款单
              logger.info("生成还款单,单号:{} 金额:{}", orderId, amount);
              // 模拟还款成功
              logger.info("还款成功,单号:{} 金额:{}", orderId, amount);
              return "0000";
          }
      
          @Override
          public List<String> tradeFlow() {
              return super.tradeFlow();
          }
      }
    
    测试类:
    /**
       * @Description: 验证测试
       * @Author: pupil
       * @Date: 2024/06/23 下午 10:33
       */
      public class ApiTest {
      
          private Logger logger = LoggerFactory.getLogger(ApiTest.class);
      
          @Test
          public void test_CashCard() {
              CashCard cashCard = new CashCard();
              // 提现
              cashCard.withdrawal("14451", new BigDecimal(100));
              // 储蓄
              cashCard.recharge("14451", new BigDecimal(100));
              // 交易流水
              List<String> tradeFlow = cashCard.tradeFlow();
              logger.info("查询交易流水,{}", JSON.toJSONString(tradeFlow));
          }
      
          @Test
          public void test_CreditCard() {
              CreditCard creditCard = new CreditCard();
              // 支付
              creditCard.withdrawal("14451", new BigDecimal(100));
              // 还款
              creditCard.recharge("14451", new BigDecimal(100));
              // 交易流水
              List<String> tradeFlow = creditCard.tradeFlow();
              logger.info("查询交易流水,{}", JSON.toJSONString(tradeFlow));
          }
      }
    
    结果:
    • 在这里插入图片描述
    • 在这里插入图片描述

    里氏替换原则替换后示例代码:

    银行卡类:
    /**
    * @Description: 银行卡
    * @Author: pupil
    * @Date: 2024/06/23 下午 10:46
    */
    public abstract class BankCard {
    
      private Logger logger = LoggerFactory.getLogger(BankCard.class);
      private static List<String> tradeList = new ArrayList<String>();
    
      private String cardId;   // 卡号
      private String cardDate; // 开卡时间
    
      public BankCard(String cardId, String cardDate) {
          this.cardId = cardId;
          this.cardDate = cardDate;
      }
    
      abstract boolean rule(BigDecimal amount);
    
    
      /**
       * 正向入账,+ 钱
       * @param orderId 单号
       * @param amount 金额
       * @return 状态码 0000成功、0001失败、0002重复
       */
      public String positive(String orderId, BigDecimal amount) {
          // 入款成功,存款、还款
          logger.info("卡号{} 入款成功,单号:{} 金额:{}", cardId, orderId, amount);
          return "0000";
      }
    
      /**
       * 逆向入账,- 钱
       * @param orderId
       * @param amount
       * @return 状态码 0000成功、0001失败、0002重复
       */
      public String negative(String orderId, BigDecimal amount) {
          // 入款成功,存款、还款
          logger.info("卡号{} 出款成功,单号:{} 金额:{}", cardId, orderId, amount);
          return "0000";
      }
    
      /**
       * 交易流水查询
       *
       * @return 交易流水
       */
      public List<String> tradeFlow() {
          logger.info("交易流水查询成功");
          tradeList.add("14451,100.00");
          tradeList.add("14451,80.00");
          tradeList.add("14451,76.50");
          tradeList.add("14451,126.00");
          return tradeList;
      }
    
      public String getCardId() {
          return cardId;
      }
    
      public String getCardDate() {
          return cardDate;
      }
    }
    
    /**
    * @Description: 模拟储蓄卡功能
    * @Author: pupil
    * @Date: 2024/06/23 下午 10:04
    */
    public class CashCard extends BankCard {
    
      private Logger logger = LoggerFactory.getLogger(CashCard.class);
    
      public CashCard(String cardNo, String cardDate) {
          super(cardNo, cardDate);
      }
    
      boolean rule(BigDecimal amount) {
          return true;
      }
    
      /**
       * 提现
       *
       * @param orderId 单号
       * @param amount  金额
       * @return 状态码 0000成功、0001失败、0002重复
       */
      public String withdrawal(String orderId, BigDecimal amount) {
          // 模拟支付成功
          logger.info("提现成功,单号:{} 金额:{}", orderId, amount);
          return super.negative(orderId, amount);
      }
    
      /**
       * 储蓄
       *
       * @param orderId 单号
       * @param amount  金额
       */
      public String recharge(String orderId, BigDecimal amount) {
          // 模拟充值成功
          logger.info("储蓄成功,单号:{} 金额:{}", orderId, amount);
          return super.positive(orderId, amount);
      }
    
    }
    
    
    
    
    信用卡类:
    /**
    * @Description: 模拟信用卡功能,重写父类的方法,违法里氏替换原则
    * @Author: pupil
    * @Date: 2024/06/23 下午 10:32
    */
    public class CreditCard extends CashCard{
    
      private Logger logger = LoggerFactory.getLogger(CashCard.class);
    
      public CreditCard(String cardNo, String cardDate) {
          super(cardNo, cardDate);
      }
    
      /**
       * 金额规则
       * 根据里氏替换原则不能重写父类的rule方法,所以新构建一个方法
       * @param amount
       * @return
       */
      boolean rule2(BigDecimal amount) {
          return amount.compareTo(new BigDecimal(1000)) <= 0;
      }
    
    
      /**
       * 提现,信用卡贷款
       *
       * @param orderId 单号
       * @param amount  金额
       * @return 状态码 0000成功、0001失败、0002重复
       */
      public String loan(String orderId, BigDecimal amount) {
          boolean rule = rule2(amount);
          if (!rule) {
              logger.info("生成贷款单失败,金额超限。单号:{} 金额:{}", orderId, amount);
              return "0001";
          }
          // 模拟生成贷款单
          logger.info("生成贷款单,单号:{} 金额:{}", orderId, amount);
          // 模拟支付成功
          logger.info("贷款成功,单号:{} 金额:{}", orderId, amount);
          return super.negative(orderId, amount);
    
      }
    
      /**
       * 还款,信用卡还款
       *
       * @param orderId 单号
       * @param amount  金额
       * @return 状态码 0000成功、0001失败、0002重复
       */
      public String repayment(String orderId, BigDecimal amount) {
          // 模拟生成还款单
          logger.info("生成还款单,单号:{} 金额:{}", orderId, amount);
          // 模拟还款成功
          logger.info("还款成功,单号:{} 金额:{}", orderId, amount);
          return super.positive(orderId, amount);
      }
    }
    
    测试类:
    /**
    * @Description: 测试验证
    * @Author: pupil
    * @Date: 2024/06/23 下午 10:51
    */
    public class ApiTest {
    
      private Logger logger = LoggerFactory.getLogger(ApiTest.class);
    
      @Test
      public void test_bankCard() {
          logger.info("里氏替换前,CashCard类:");
          CashCard bankCard = new CashCard("800999898", "2024-06-23");
          // 提现
          bankCard.withdrawal("14451", new BigDecimal(100));
          // 储蓄
          bankCard.recharge("14451", new BigDecimal(100));
    
          logger.info("里氏替换后,CreditCard类:");
          CashCard creditCard = new CreditCard("800999898", "2024-06-23");
          // 提现
          creditCard.withdrawal("14451", new BigDecimal(1000000));
          // 储蓄
          creditCard.recharge("14451", new BigDecimal(100));
    
          // 交易流水
          List<String> tradeFlow = bankCard.tradeFlow();
          logger.info("查询交易流水,{}", JSON.toJSONString(tradeFlow));
      }
    
      @Test
      public void test_CreditCard(){
          CreditCard creditCard = new CreditCard("800999898", "2024-06-23");
          // 支付,贷款
          creditCard.loan("14451", new BigDecimal(100));
          // 还款
          creditCard.repayment("14451", new BigDecimal(100));
    
          // 交易流水
          List<String> tradeFlow = creditCard.tradeFlow();
          logger.info("查询交易流水,{}", JSON.toJSONString(tradeFlow));
      }
    }
    
    结果:
    • 在这里插入图片描述

    • 在这里插入图片描述

    根据里氏替换原则的示例类图:

    在这里插入图片描述

    银行卡和储蓄卡是泛化关系,储蓄卡继承于银行卡

    储蓄卡和信用卡是泛化关系,信用卡继承于储蓄卡

  • 相关阅读:
    网络设备的部署(串行与并行)
    回调地狱(嵌套金字塔)及promise语法
    手写一个博客平台 ~ 第五天
    数字图像处理实验记录三(双线性插值和最邻近插值)
    攻防演练-安全监测岗都做哪些工作
    JavaWeb之初识Tomcat
    mysql高级篇
    今天又做了三个梦,其中一个梦梦里的我还有意识会思考?
    超好用,分享8个 Python 自动化脚本
    这绝对是总结的最详细的自动化测试基础知识学习
  • 原文地址:https://blog.csdn.net/luck_lsj/article/details/139908765