java面向对象学习
今天b站学习java的面向对象的时候视频提到的这个案例
看到了这一堆需求以后我上来就是一套
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入您的车牌号:");
String licensePlate = scanner.next();
System.out.println("请输入您的用户名:");
String userName = scanner.next();
System.out.println("请输入您的手机号:");
String ownerPhone = scanner.next();
System.out.println("请输入您的余额:");
double balance = scanner.nextDouble();
if (balance >= 5000) {
System.out.println("恭喜,办金卡成功,您的卡号为:" + licensePlate);
Card card = new GoldCard(licensePlate, userName, ownerPhone, balance);
card.showInfo();
//输入本次消费金额
System.out.println("请输入本次消费金额:");
double amount = scanner.nextDouble();
card.pay(amount);
} else if (balance >= 2000) {
System.out.println("恭喜,办银卡成功,您的卡号为:" + licensePlate);
Card card = new SilverCard(licensePlate, userName, ownerPhone, balance);
card.showInfo();
//输入本次消费金额
System.out.println("请输入本次消费金额:");
double amount = scanner.nextDouble();
card.pay(amount);
} else {
System.out.println("您的余额太少,暂不支持办卡");
}
}
}
class Card {
private String licensePlate;
private String userName;
private String ownerPhone;
private double balance;
public Card() {
}
public Card(String licensePlate, String userName, String ownerPhone, double balance) {
this.licensePlate = licensePlate;
this.userName = userName;
this.ownerPhone = ownerPhone;
this.balance = balance;
}
public void pay(double amount) {
setBalance(getBalance() - amount);
System.out.println("支付成功,剩余余额为:" + getBalance());
}
public void showInfo() {
System.out.println("车牌号:" + getLicensePlate() + "\n用户名:" + getUserName() + "\n手机号:" + getOwnerPhone() + "\n余额:" + getBalance());
}
// 省略了getter和setter
}
class GoldCard extends Card {
public GoldCard() {
}
public GoldCard(String licensePlate, String userName, String ownerPhone, double balance) {
super(licensePlate, userName, ownerPhone, balance);
}
@Override
public void pay(double amount) {
setBalance(getBalance() - amount * 0.8);
System.out.println("支付成功,剩余余额为:" + getBalance());
isEligibleForFreeCarWash(amount);
}
public void isEligibleForFreeCarWash(double amount) {
if (amount >= 200) {
System.out.println("恭喜,您本次消费" + amount + "元,获得免费洗车服务");
}
}
}
//银卡
class SilverCard extends Card {
public SilverCard() {
}
public SilverCard(String licensePlate, String userName, String ownerPhone, double balance) {
super(licensePlate, userName, ownerPhone, balance);
}
@Override
public void pay(double amount) {
setBalance(getBalance() - amount * 0.9);
System.out.println("支付成功,剩余余额为:" + getBalance());
}
}
多么完美的封装继承,Card包含卡片信息,然后Card再写一个公共的支付函数,我再用金卡银卡一重写,等用的时候我一个Card card = new GoldCard()然后统一调用card.pay又体现了多态。
但是作为一个学过设计模式的人,我稍加思索突然发觉一丝丝的不对劲!
- 首先最明显的是pay这个函数重复了很多次。而且再每一个子类里面都要重写一次,差别就仅仅是打折的钱数不同。
- 再者假如我以后要修改pay的打折逻辑,我岂不是要点进每一个子类的pay方法里面去改。
于是乎想到这里可以用策略模式进行改进,我在Card类里面去存一个打折策略的接口,以后如果要加什么钻石卡,或者打折整体的规则都变了比如按200-300 400-500分段打折等等我就只去策略类里面去改就好了。
策略模式的UML类图是这样的所以我们设计的时候需要一个抽象的策略类,也体现了一个依赖倒置原则,就是依赖于抽象类而不是具体类。这样的好处是Card里面我存的是抽象策略,所以我不需要去改这个地方的代码。
可以把金卡打折还有消费满200写成金卡策略类的两个方法,并且呢不让他俩互相调用,要用一个外部的operator类来组合他俩。而且要用外部的类来调用card并且根据不同的card的策略进行相应的操作。
所以就有了更改后的版本。
// 折扣策略接口
public interface DiscountStrategy {
double calculateDiscount(double amount);
}
// 银卡策略实现
public class SilverCard implements DiscountStrategy {
@Override
public double calculateDiscount(double amount) {
// 银卡折扣逻辑
return amount * 0.95; // 假设银卡打95折
}
}
// 金卡策略实现
public class GoldCard implements DiscountStrategy {
@Override
public double calculateDiscount(double amount) {
// 金卡折扣逻辑
return amount * 0.90; // 假设金卡打9折
}
public boolean isEligibleForFreeCarWash(double amount) {
return amount >= 200;
}
}
// 卡片类
public class Card {
private String licensePlate;
private String ownerPhone;
private double balance;
private DiscountStrategy discountStrategy;
public Card(String licensePlate, String ownerPhone, double balance, DiscountStrategy discountStrategy) {
this.licensePlate = licensePlate;
this.ownerPhone = ownerPhone;
this.balance = balance;
this.discountStrategy = discountStrategy;
}
// 省略getter和setter方法
}
// 支付服务
public class PaymentService {
public void processPayment(Card card, double amount) {
double discountAmount = card.getDiscountStrategy().calculateDiscount(amount);
card.setBalance(card.getBalance() - discountAmount);
if (card.getDiscountStrategy() instanceof GoldCard && ((GoldCard) card.getDiscountStrategy()).isEligibleForFreeCarWash(amount)) {
// 提供免费洗车服务
}
}
}
// 工厂类
public class CardFactory {
public static Card createCard(String type, String licensePlate, String ownerPhone, double balance) {
DiscountStrategy strategy;
if ("gold".equals(type)) {
strategy = new GoldCard();
} else {
strategy = new SilverCard();
}
return new Card(licensePlate, ownerPhone, balance, strategy);
}
}
可以看出以后要修改打折逻辑只需要增加或者修改已经有的策略类符合开闭原则,Card类基本不用动了,而且Card类现在是javabean实体类风格只负责数据的存取不负责对数据的操作。对数据的操作通过另一个操作类PaymentService。
增强了维护性提高复用性巴拉巴拉。。。