定义:继承必须确保超类所拥有的性质在子 类中仍然成立
里氏替换原则:
如果S是T的子类,那么所有T类型的对象都可以在不破换程序的情况下被S类型的对象替换
简单来说,子类可以扩展父类的功能,但是不能改变父类原有的功能。也就是说:当子类继承父类时,除了添加新的方法且完成新增功能外,尽量不能重新父类的方法。这句话包含了四点:
1.子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法
2.子类可以增加自己特有的方法
3.当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松
当子类的方法实现父类的方法(重载、重写或实现抽象方法)时,方法的后置条件(即方法的输出或者返回值)要比父类的方法更严格或者与父类的方法相等。
里氏替换原则的作用:
1.里氏替换原则是实现开闭原则的重要的方式之一
2.解决了继承中的重写父类造成的可复用性变差的问题
3.是动作正确性的保证,即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性
4.加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性,可扩展性,降低需求变更时引入的风险
原始方法代码实现:
public class CashCard {
/**
* 在储蓄卡的功能实现中包括了三个方法:提现、储蓄、交易流水查询,这些都是模拟储蓄卡的基本功能
*/
public Logger logger = LoggerFactory.getLogger(CashCard.class);
/**
* 提现
* @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 状态码
*/
public String recharge(String orderId,BigDecimal amount) {
//模拟充值功能
logger.info("储蓄成功,单号:{} 金额:{}",orderId,amount);
return "0000";
}
/**
* 交易流水查询
* @return
*/
public List<String> tradeFlow() {
logger.info("交易流水查询成功");
List<String> tradeList = new ArrayList<>();
tradeList.add("100001,100.00");
tradeList.add("100001,80.00");
tradeList.add("100001,76.00");
tradeList.add("100001,126.00");
return tradeList;
}
}
public class CreditCard extends CashCard {
private Logger logger = LoggerFactory.getLogger(CreditCard.class);
/**
* 贷款功能
* @param orderId 单号
* @param amount 金额
* @return
*/
@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
*/
@Override
public String recharge(String orderId, BigDecimal amount) {
//模拟生成还款单
logger.info("生成还款单,单号:{} 金额:{}" ,orderId,amount);
//模拟还款成功
logger.info("还款成功,订单号:{} 金额:{}",orderId,amount);
return "0000";
}
/**
* 打印信用卡流水详情
* @return
*/
@Override
public List<String> tradeFlow() {
return super.tradeFlow();
}
/**
* 信用卡功能呢的实现是在继承了储蓄卡的类之后,进行方法的重写:支付方法,还款方法,打印流水方法
* 其实也可以不用重写这个方法,可以复用
*/
}
里氏替换代码实现:
public abstract class BackCard {
/**
* 在抽象银行卡类中,提供了基本卡的属性,包括卡号、开卡时间、及三个核心方法。
* 正向入账 加钱
* 逆向入账 减钱
* 查询交易流水
*/
private Logger logger = LoggerFactory.getLogger(BackCard.class);
private String cardNo; //卡号
private String cardDate; //开卡时间
public BackCard(String cardNo, String cardDate) {
this.cardNo = cardNo;
this.cardDate = cardDate;
}
//规则
abstract boolean rule(BigDecimal amount);
/**
* 正向入账,加钱
* @param orderId
* @param amount
* @return
*/
public String positive(String orderId,BigDecimal amount) {
//入款成功 存款、还款
logger.info("卡号() 入款成功,单号:{} 金额:{}" ,cardNo,orderId,amount);
return "0000";
}
public String negative(String orderId,BigDecimal amount){
//出款成功,存款 还款
logger.info("卡号() 出款成功,单号:{} 金额:{}" ,cardNo,orderId,amount);
return "0000";
}
/**
* 交易流水查询
* @return
*/
public List<String> tradeFlow(){
logger.info("交易流水查询成功");
List<String> tradeList = new ArrayList<>();
tradeList.add("100001,100.00");
tradeList.add("100001,80.00");
tradeList.add("100001,76.00");
tradeList.add("100001,126.00");
return tradeList;
}
public String getCardNo(){
return cardNo;
}
public String getCardDate(){
return cardDate;
}
}
public class BackTest {
public static void main(String[] args) {
CashCard backCard = new CashCard("966356985233366", "2022-02-22");
//提现
backCard.withdrawal("100001", new BigDecimal(100));
//储存
backCard.recharge("100001", new BigDecimal(100));
}
}
public class CashCard extends BackCard {
private Logger logger = LoggerFactory.getLogger(CashCard.class);
public CashCard(String cardNo, String cardDate) {
super(cardNo, cardDate);
}
/**
* 规则过滤,储蓄卡直接默认通过
* @param amount
* @return
*/
@Override
boolean rule(BigDecimal amount) {
return true;
}
/**
* 提现
* @param orderId
* @param amount
* @return
*/
public String withdrawal(String orderId,BigDecimal amount) {
//模拟支付成功
logger.info("模拟体现成功,单号:{} 金额:{}" ,orderId,amount);
return super.negative(orderId,amount);
}
/**
* 储蓄
* @param orderId
* @param amount
* @return
*/
public String recharge(String orderId,BigDecimal amount) {
//模拟储蓄成功
logger.info("储蓄成功,订单号:{} 金额:{}",orderId,amount);
return super.positive(orderId, amount);
}
/**
* 功能增强 风险校验
* @param cardNo 卡号
* @param orderId 单号
* @param amount 金额
* @return 状态
*/
public boolean checkRisk(String cardNo,String orderId,BigDecimal amount){
//模拟风控校验
logger.info("风控校验,卡号{} 单号:{} 金额:{}",cardNo,orderId,amount);
return true;
}
/**
* 这样的实现方式基本满足了里氏替换原则的基本的原则,既实现抽象类的抽象方法,又没有破坏父类中原有的方法
*/
}
public class CreditCard extends CashCard {
private Logger logger = LoggerFactory.getLogger(CreditCard.class);
public CreditCard(String cardNo, String cardDate) {
super(cardNo, cardDate);
}
boolean rule2(BigDecimal amount) {
return amount.compareTo(new BigDecimal(1000)) <= 0;
}
/**
* 提现,信用卡贷款
* @param orderId
* @param amount
* @return
*/
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
*/
public String repayment(String orderId,BigDecimal amount) {
//模拟生成还款单
logger.info("生成还款单,单号:{} 金额:{}",orderId,amount);
//模拟还款成功
logger.info("还款成功,单号:{} 金额:{}",orderId,amount);
return super.positive(orderId, amount);
}
/**
* 信用卡类在继承了储蓄卡类之后,使用了公共的属性,即卡号 开卡时间 同时新增了符合信用卡功能的新方法,即贷款、还款,并在两个方法中都使用了抽象类的核心功能
*/
}