设计模式原则
设计模式示例代码库地址:
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));
}
}
结果:
根据里氏替换原则的示例类图:
银行卡和储蓄卡是泛化关系,储蓄卡继承于银行卡
储蓄卡和信用卡是泛化关系,信用卡继承于储蓄卡