Liskov Substitution Principle,LSP
。
design-1.3-0
|——src
|——main
|--java
|--com.lino.design
|--CashCard.java
|--CreditCard.java
|——test
|--java
|--com.lino.design.test
|--ApiTest.java
CashCard.java
package com.lino.design;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 模拟储蓄卡功能
*/
public class CashCard {
private 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 状态码 0000成功、0001失败、0002重复
*/
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.50");
tradeList.add("100001,126.00");
return tradeList;
}
}
CreditCard.java
package com.lino.design;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.List;
/**
* @description: 模拟信用卡功能
*/
public class CreditCard extends CashCard {
private Logger logger = LoggerFactory.getLogger(CreditCard.class);
@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";
}
@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();
}
}
withdrawal()
、还款 recharge()
。交易流水可以复用,不用重写这个类。ApiTest.java
@Test
public void test_CashCard() {
CashCard cashCard = new CashCard();
// 提现
cashCard.withdrawal("100001", new BigDecimal(100));
// 储蓄
cashCard.recharge("100001", new BigDecimal(100));
// 交易流水
List<String> tradeFlow = cashCard.tradeFlow();
logger.info("查询交易流水:{}", JSON.toJSONString(tradeFlow));
}
测试结果
10:58:28.027 [main] INFO com.lino.design.CashCard - 提现成功,单号:100001 金额:100
10:58:28.031 [main] INFO com.lino.design.CashCard - 储值成功,单号:100001 金额:100
10:58:28.031 [main] INFO com.lino.design.CashCard - 交易流水查询成功
10:58:28.169 [main] INFO com.lino.design.test.ApiTest - 查询交易流水:["100001,100.00","100001,80.00","100001,76.50","100001,126.00"]
ApiTest.java
@Test
public void test_CreditCard() {
CreditCard creditCard = new CreditCard();
// 支付
creditCard.withdrawal("100001", new BigDecimal(100));
// 还款
creditCard.recharge("100001", new BigDecimal(100));
// 交易流水
List<String> tradeFlow = creditCard.tradeFlow();
logger.info("查询交易流水:{}", JSON.toJSONString(tradeFlow));
}
测试结果
10:59:23.970 [main] INFO com.lino.design.CreditCard - 生成贷款单,单号:100001 金额:100
10:59:23.970 [main] INFO com.lino.design.CreditCard - 贷款成功,单号:100001 金额:100
10:59:23.970 [main] INFO com.lino.design.CreditCard - 生成还款单,单号:100001 金额:100
10:59:23.970 [main] INFO com.lino.design.CreditCard - 还款成功,单号:100001 金额:100
10:59:23.970 [main] INFO com.lino.design.CashCard - 交易流水查询成功
10:59:24.003 [main] INFO com.lino.design.test.ApiTest - 查询交易流水:["100001,100.00","100001,80.00","100001,76.50","100001,126.00"]
design-1.3-1
|——src
|——main
|--java
|--com.lino.design
|--BandCard.java
|--CashCard.java
|--CreditCard.java
|——test
|--java
|--com.lino.design.test
|--ApiTest.java
BandCard.java
package com.lino.design;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 银行卡
*/
public abstract class BandCard {
private Logger logger = LoggerFactory.getLogger(BandCard.class);
/**
* 卡号
*/
private String cardNo;
/**
* 开卡时间
*/
private String cardDate;
public BandCard(String cardNo, String cardDate) {
this.cardNo = cardNo;
this.cardDate = cardDate;
}
/**
* 金额判断规则
*
* @param amount 金额
* @return 是否符合规则
*/
abstract boolean rule(BigDecimal amount);
/**
* 正向入账:+钱
*
* @param orderId 单号
* @param amount 金额
* @return 状态码
*/
public String positive(String orderId, BigDecimal amount) {
// 入款成功,存款、还款
logger.info("卡号{} 入款成功:单号:{} 金额:{}", cardNo, orderId, amount);
return "0000";
}
/**
* 逆向入账:-钱
*
* @param orderId 单号
* @param amount 金额
* @return 状态码
*/
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.50");
tradeList.add("100001,126.00");
return tradeList;
}
public String getCardNo() {
return cardNo;
}
public String getCardDate() {
return cardDate;
}
}
CashCard.java
package com.lino.design;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
/**
* @description: 模拟储值卡功能
*/
public class CashCard extends BandCard {
private Logger logger = LoggerFactory.getLogger(CashCard.class);
public CashCard(String cardNo, String cardDate) {
super(cardNo, cardDate);
}
@Override
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 金额
* @return 状态码 0000成功、0001失败、0002重复
*/
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;
}
}
BandCard
,实现的核心功能包括规则过滤 rule
、提现 withdrawal
、储蓄 recharge
和新增的扩展方法,即风控校验 checkRisk
。CreditCard.java
package com.lino.design;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
/**
* @description: 信用卡
*/
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);
}
}
cardNo
、开卡时间 cardDate
,同时新增了符合信用卡功能的新方法,即贷款 loan
、还款 repayment
,并在两个方法中都使用了抽象类的核心功能。rule2
,并没有破坏储蓄卡中的校验方法。ApiTest.java
@Test
public void test_bandCard() {
logger.info("里氏替换前,CashCard类:");
CashCard bandCard = new CashCard("6214567800989876", "2022-12-14");
// 提现
bandCard.withdrawal("100001", new BigDecimal(100));
// 储蓄
bandCard.recharge("100001", new BigDecimal(100));
logger.info("里氏替换后,CreditCard类:");
CashCard creditCard = new CreditCard("6214567800989876", "2022-12-14");
// 提现
creditCard.withdrawal("100001", new BigDecimal(1000000));
// 储蓄
creditCard.recharge("100001", new BigDecimal(100));
}
测试结果
11:16:03.817 [main] INFO com.lino.design.test.ApiTest - 里氏替换前,CashCard类:
11:16:03.817 [main] INFO com.lino.design.CashCard - 提现成功,单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 出款成功:单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.CashCard - 储值成功,单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 入款成功:单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.test.ApiTest - 里氏替换后,CreditCard类:
11:16:03.817 [main] INFO com.lino.design.CashCard - 提现成功,单号:100001 金额:1000000
11:16:03.817 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 出款成功:单号:100001 金额:1000000
11:16:03.817 [main] INFO com.lino.design.CashCard - 储值成功,单号:100001 金额:100
11:16:03.817 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 入款成功:单号:100001 金额:100
ApiTest.java
@Test
public void test_CreditCard() {
CreditCard creditCard = new CreditCard("6214567800989876", "2022-12-14");
// 支付,贷款
creditCard.loan("100001", new BigDecimal(100));
// 还款
creditCard.repayment("100001", new BigDecimal(100));
}
测试结果
11:13:03.042 [main] INFO com.lino.design.CreditCard - 生成贷款单,单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.CreditCard - 贷款成功,单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 出款成功:单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.CreditCard - 生成还款单,单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.CreditCard - 还款成功,单号:100001 金额:100
11:13:03.042 [main] INFO com.lino.design.BandCard - 卡号6214567800989876 入款成功:单号:100001 金额:100
CashCard creditCard = new CreditCard()
。