目录
引言
要知道设计模式就是软件工程的方法经验的总结,也是可以认为是过去一段时间软件工程的一个最佳实践,要理解,不要死记硬背。掌握这些方法后,可以让你的程序获得以下好处:
- 代码重用性(相同功能的代码,不用多次编写)
- 可读性(编程规范性,便于其他程序员的阅读和理解)
- 可扩展性(当需要增加新的功能时,非常的方便,称为可维护)
- 可靠性(当我们增加新的功能后,对原来的功能没有影响)
- 使程序呈现高内聚,低耦合的特性。
当然设计是有限度的,不能无限的考虑未来的变更情况,否则就会陷入设计的泥潭而无法自拔。方法是死的,人是活,用的时候一定灵活运用,才能发挥它的作用。设计模式中六大设计原则,这些原则可以认为是设计模式的灵昏。下面先对六大设计原则简单梳理一下,然后再详细分析每一个设计原则。
单一职责原则
我们现在的智能手机往往包含许多功能,拍照、打电话、打游戏等等。假设我们此时要拍一个美景,我们会发现手机拍下来的不如摄像机拍下来的清晰,因为摄像机就是专门干拍照这事儿的。
所以大多数时候,一件产品简单一些,职责单一一些,或许是更好的选择。
单一职责原则:就一个类而言,应该只有一个引起它变化的原因。
如果一个类承担的职责过多,就等于把职责都耦合在了一起,这样一个职责的变化可能削弱或者抑制这个类完成其他职责的能力。
就比如你要开发一个俄罗斯方块的游戏,它分为手机版和电脑版。游戏逻辑和界面是不互相影响的,游戏逻辑在哪个界面都是可以被复用的,所以将界面的变化和游戏逻辑分离开,单一职责,有利于界面的改动。
开闭原则
拿香港回归举例,如果当时一口咬定回归之后要改为社会主义制度,那回归的难度可谓困难重重,那既然不能改变原有的制度,我们可以考虑扩展,采用一国两制,是一种伟大的发明。
在设计模式中,这种不能修改但可以扩展的思想就是开闭原则。
开闭原则:软件实体(类、模块、函数等)应该可以扩展,但是不可修改
里氏替换原则
继承必须确保父类所拥有的性质在子类中仍然成立。
里氏替换原则的问题由来
有一功能 P1,由类 A 完成。
现需要将功能 P1 进行扩展,扩展后的功能为 P,其中P由原有功能 P1 与新功能 P2 组成。
新功能 P 由类 A 的子类 B 来完成,则子类 B 在完成新功能 P2 的同时,有可能会导致原有功能 P1 发生故障。
里氏替换的原则
如果S是T的子类型,那么所有T类型的对象都可以在不破坏程序的情况下被S类型的对象替换。
简单来说: 子类可以扩展父类的功能,但不能改变父类原有的功能。 也就是说,当子类继承父类时,除了添加新的方法完成新增功能外,尽量不要重写父类的方法。
四点含义:
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
- 子类可以增加自己特有的方法
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类更宽松
- 当子类的方法实现父类的方法(重写、重载或者实现抽象方法)时,方法的后置条件(即方法的输出或者返回值)要比父类的方法更严格或与父类的方法相等
Case
用个银行卡的场景来描述一下:
储蓄卡、信用卡都可以消费,但信用卡不宜提现,否则产生高额利息。两个类
- 储蓄卡类
- 信用卡类
Bad Impl(违反原则)
【储蓄卡】
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 金额
*/
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<String>();
tradeList.add("100001,100.00");
tradeList.add("100001,80.00");
tradeList.add("100001,76.50");
tradeList.add("100001,126.00");
return tradeList;
}
}
在储蓄卡中包括三个方法: 提现、储蓄、交易流水查询, 这都是模拟储蓄卡的基本功能。
接下来我们通过继承储蓄卡的功能实现信用卡的服务。
【信用卡】
public class CreditCard extends CashCard {
private Logger logger = LoggerFactory.getLogger(CashCard.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();
}
信用卡的功能实现是在继承了储蓄卡后,进行方法的重写: 支付、还款。 其实交易流水可以复用,也可以不用重写这个。
那看看单元测试是如何使用的?
public class Test {
private Logger logger = LoggerFactory.getLogger(ApiTest.class);
@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));
}
@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));
}
}
这种继承父类方式的优点是复用了父类的核心逻辑功能, 但是也破坏了原有的方法。 此时继承父类实现的信用卡的类并不满足里氏替换的原则。也就是说,此时的子类不能承担原父类的功能,直接给储蓄卡使用。
Better Impl (遵守原则)
信用卡和储蓄卡在功能上有些许类似,在实际开发的过程中也有很多共同的可服用的属性及逻辑。
实现这样的类的最好的方式就是提取出一个抽象类 , 由抽象类定义所有卡的共同核心属性、逻辑, 把卡的支付和还款等动作抽象成正向和逆向操作。
抽象银行卡类
public abstract class BankCard {
private Logger logger = LoggerFactory.getLogger(BankCard.class);
private String cardNo; // 卡号
private String cardDate; // 开卡时间
public BankCard(String cardNo, String cardDate) {
this.cardNo = cardNo;
this.cardDate = cardDate;
}
abstract boolean rule(BigDecimal amount);
// 正向入账,+ 钱
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<String>();
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;
}
}
抽象类中提供了卡的基本属性(卡号、开卡时间)及 核心方法。
正向入账: 加钱 逆向入账: 减钱。
接下来我们继承这个抽象类,实现储蓄卡的功能逻辑
储蓄卡实现类
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);
}
/**
* 风险校验
*
* @param cardNo 卡号
* @param orderId 单号
* @param amount 金额
* @return 状态
*/
public boolean checkRisk(String cardNo, String orderId, BigDecimal amount) {
// 模拟风控校验
logger.info("风控校验,卡号:{} 单号:{} 金额:{}", cardNo, orderId, amount);
return true;
}
}
储蓄卡类继承抽象父类BankCard ,实现了核心的功能包括规则过滤rule、提现、储蓄 (super.xx), 以及新增的扩展方法:风险校控checkRisk.
这样的实现方式基本满足里氏替换的基本原则:既实现抽象类的抽象方法,又没有破坏父类中的原有方法。
接下来的信用卡类,既可以继承抽象父类,也可以继承储蓄卡类, 但无论那种实现方式,都需要遵从里氏替换原则,不可以破坏父类原有的方法。
信用卡实现类
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);
}
}
信用卡类在继承父类后,使用了公共的属性,即卡号、开卡时间, 同时新增了符合信用卡的新方法: loan、repayment, 并且在两个方法中都使用了抽象类的核心功能。
另外,信用卡中新增了自己的规则rule2 , 并没有破坏储蓄卡中的校验方法rule .
以上的实现方式都遵循了里氏替换原则下完成的,即信用卡类(子类)可以随时替代储蓄卡类(父类)
单元测试
【测试储蓄卡】
@Test
public void test_bankCard() {
logger.info("里氏替换前,CashCard类:");
CashCard bankCard = new CashCard("123456", "2023-01-01");
// 提现
bankCard.withdrawal("100001", new BigDecimal(100));
// 储蓄
bankCard.recharge("100001", new BigDecimal(100));
}
【测试信用卡】
@Test
public void test_CreditCard(){
CreditCard creditCard = new CreditCard("123456", "2023-01-01");
// 支付,贷款
creditCard.loan("100001", new BigDecimal(100));
// 还款
creditCard.repayment("100001", new BigDecimal(100));
}
【测试信用卡替换储蓄卡】
@Test
public void test_bankCard() {
logger.info("里氏替换后,CreditCard类:");
CashCard creditCard = new CreditCard("123456", "2023-01-01");
// 提现
creditCard.withdrawal("100001", new BigDecimal(1000000));
// 储蓄
creditCard.recharge("100001", new BigDecimal(100));
}
可以看到,储蓄卡功能正常, 继承储蓄卡实现的信用卡的功能也正常。
同时,原有储蓄卡的功能可以由信用卡类支持
总结起来,里氏替换原则强调了继承关系的正确使用,要求子类能够完全替代父类,而不破坏程序的正确性。遵循该原则可以提高代码的重用性、灵活性和可靠性
迪米特法则
迪米特法则:意义在于降低类之间的耦合。由于每个对象尽量减少对其他对象的了解,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。
Case
Bad Impl(违反原则)
// 员工类
public class Employee {
private String name;
public Employee(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 部门类
public class Department {
private List<Employee> employees = new ArrayList<>();
private String name;
public Department(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void addEmployee(Employee employee) {
employees.add(employee);
}
public List<Employee> getEmployees() {
// 暴露内部细节
return employees;
}
}
// 公司类 - 直接访问了Department的内部结构(Employee)
public class Company {
private List<Department> departments = new ArrayList<>();
public void addDepartment(Department department) {
departments.add(department);
}
// 违反迪米特法则:直接操作了间接关联的Employee对象
public void printAllEmployees() {
for (Department department : departments) {
System.out.print(department.getName() + "部门员工列表:");
// 直接访问部门内部的员工列表
for (Employee employee : department.getEmployees()) {
System.out.print(employee.getName() + " ");
}
System.out.println();
}
}
}
测试程序
public class Test {
public static void main(String[] args) {
// 创建员工
Employee zhang = new Employee("张三");
Employee li = new Employee("李四");
Employee wang = new Employee("王五");
// 创建部门
Department department = new Department("技术部");
// 部门添加员工
department.addEmployee(zhang);
department.addEmployee(li);
department.addEmployee(wang);
Company company = new Company();
company.addDepartment(department);
// 公司查询所有部门员工
company.printAllEmployees();
}
}
问题:Company 直接访问了 Department 的内部结构(Employee 列表),这导致:
- 高层类依赖底层类实现细节
- 修改 Department 内部结构时会影响 Company
- 耦合度过高
Better Impl (遵守原则)
// 员工类(不变)
class Employee {
private String name;
public Employee(String name) { this.name = name; }
public String getName() { return name; }
}
// 部门类 - 封装对Employee的操作
public class Department {
private List<Employee> employees = new ArrayList<>();
private String name;
public Department(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void addEmployee(Employee employee) {
employees.add(employee);
}
public void printDepartmentEmployees() {
for (Employee e : employees) {
System.out.print(e.getName() + " ");
}
}
}
// 公司类 - 只与直接朋友Department交互
public class Company {
private List<Department> departments = new ArrayList<>();
public void addDepartment(Department department) {
departments.add(department);
}
// 遵守迪米特法则:仅调用直接关联对象的方法
public void printAllEmployees() {
for (Department d : departments) {
// 委托给Department完成操作
System.out.print(d.getName() + "部门员工列表:");
d.printDepartmentEmployees();
System.out.println();
}
}
}
测试程序
public class Test {
public static void main(String[] args) {
// 创建员工
Employee zhang = new Employee("张三");
Employee li = new Employee("李四");
Employee wang = new Employee("王五");
// 创建部门
Department department = new Department("技术部");
// 部门添加员工
department.addEmployee(zhang);
department.addEmployee(li);
department.addEmployee(wang);
Company company = new Company();
company.addDepartment(department);
// 公司查询所有部门员工
company.printAllEmployees();
}
}
改进点:
- Company 只与直接朋友 Department 交互
- Department 封装了内部操作逻辑
- 底层实现变化时(如改用Set存储员工),Company 不受影响
接口隔离原则
要求程序员尽量将臃肿庞大的接口拆分为更小和更具体的接口,让接口中只包含客户感兴趣的方法。
假设你是一名餐厅的服务员,你负责为客人提供服务。根据接口隔离原则,你应该将服务拆分为多个小功能,例如点菜、上菜、结账等。这样,当客人只需要点菜时,你只提供点菜的服务;而当客人需要结账时,你则提供结账的服务。通过拆分服务功能,你可以根据客人的需求提供最小集合的服务,避免不必要的依赖和冗余。
优点
- 减少类之间的耦合:拆分接口可以减少类对接口的依赖,降低耦合度。
- 提高代码的可读性和可维护性:接口精简明确,使得代码更加清晰、易读、易于维护。
缺点
- 会增加接口的数量:拆分接口会增加接口的数量,可能导致接口过多的情况,需要权衡接口的设计。
- 可能引入接口的重复定义:当多个类需要相同的接口功能时,可能需要重复定义接口,增加了代码冗余。
适合场景
- 当一个接口定义过大,包含了多个不相关或不常用的方法时,可以考虑将其拆分为多个小接口
- 当一个类依赖的接口中包含了它不需要的方法时,可以通过接口隔离原则将接口拆分,使得类只依赖于自己所需的最小接口。
Case
Bad Impl(违反原则)
// 饭店接口
public interface RestaurantService {
// 点菜
void takeOrder(String dish);
// 上菜
void serveFood(String dish);
// 结账
void processPayment(double amount);
// 清理
void cleanTable();
// 处理投诉
void handleComplaint();
}
// 服务员
// 服务员必须实现所有方法,即使有些服务不是由服务员提供的
public class Waiter implements RestaurantService{
private String name;
public Waiter(String name) {
this.name = name;
}
@Override
public void takeOrder(String dish) {
System.out.println(name + " 记录点菜: " + dish);
}
@Override
public void serveFood(String dish) {
System.out.println(name + " 上菜: " + dish);
}
@Override
public void processPayment(double amount) {
System.out.println(name + " 收银: ¥" + amount);
}
@Override
public void cleanTable() {
// 服务员不应该负责清洁桌子
System.out.println(name + " 不情愿地清洁桌子...");
}
@Override
public void handleComplaint() {
System.out.println(name + " 处理投诉");
}
}
测试程序
public class Test {
public static void main(String[] args) {
Waiter waiter = new Waiter("小王");
waiter.takeOrder("西红柿鸡蛋面");
waiter.serveFood("西红柿鸡蛋面");
waiter.processPayment(10);
waiter.cleanTable();
waiter.handleComplaint();
}
}
测试结果如图
Better Impl (遵守原则)
interface OrderService {
void takeOrder(String dish);
}
interface FoodService {
void serveFood(String dish);
}
interface PaymentService {
void processPayment(double amount);
}
interface CleaningService {
void cleanTable();
}
interface ComplaintService {
void handleComplaint();
}
// 服务员专注于点菜、上菜和处理投诉
class ProfessionalWaiter implements OrderService, FoodService, ComplaintService {
private String name;
public ProfessionalWaiter(String name) {
this.name = name;
}
@Override
public void takeOrder(String dish) {
System.out.println(name + " 专业记录: " + dish);
}
@Override
public void serveFood(String dish) {
System.out.println(name + " 优雅地上菜: " + dish);
}
@Override
public void handleComplaint() {
System.out.println(name + " 礼貌地处理投诉");
}
}
// 清洁工负责清洁工作
class Cleaner implements CleaningService {
private String name;
public Cleaner(String name) {
this.name = name;
}
@Override
public void cleanTable() {
System.out.println(name + " 高效地清洁桌子");
}
}
// 收银员负责结账
class Cashier implements PaymentService {
private String name;
public Cashier(String name) {
this.name = name;
}
@Override
public void processPayment(double amount) {
System.out.println(name + " 专业收银: ¥" + amount);
}
}
// 餐厅管理类
public class Restaurant {
private List<OrderService> orderServices = new ArrayList<>();
private List<FoodService> foodServices = new ArrayList<>();
private List<PaymentService> paymentServices = new ArrayList<>();
private List<CleaningService> cleaningServices = new ArrayList<>();
private List<ComplaintService> complaintServices = new ArrayList<>();
public void addOrderService(OrderService service) {
orderServices.add(service);
}
public void addFoodService(FoodService service) {
foodServices.add(service);
}
public void addPaymentService(PaymentService service) {
paymentServices.add(service);
}
public void addCleaningService(CleaningService service) {
cleaningServices.add(service);
}
public void addComplaintService(ComplaintService service) {
complaintServices.add(service);
}
public void takeOrder(String dish) {
if (!orderServices.isEmpty()) {
orderServices.get(0).takeOrder(dish);
}
}
public void serveFood(String dish) {
if (!foodServices.isEmpty()) {
foodServices.get(0).serveFood(dish);
}
}
public void processPayment(double amount) {
if (!paymentServices.isEmpty()) {
paymentServices.get(0).processPayment(amount);
}
}
public void cleanTable() {
if (!cleaningServices.isEmpty()) {
cleaningServices.get(0).cleanTable();
}
}
public void handleComplaint() {
if (!complaintServices.isEmpty()) {
complaintServices.get(0).handleComplaint();
}
}
}
测试程序
public class Test {
public static void main(String[] args) {
ProfessionalWaiter professionalWaiter = new ProfessionalWaiter("李四");
Cleaner cleaner = new Cleaner("王阿姨");
Cashier cashier = new Cashier("赵会计");
// 创建餐厅并添加服务
Restaurant restaurant = new Restaurant();
restaurant.addOrderService(professionalWaiter);
restaurant.addFoodService(professionalWaiter);
restaurant.addPaymentService(cashier);
restaurant.addCleaningService(cleaner);
restaurant.addComplaintService(professionalWaiter);
// 客人体验服务
restaurant.takeOrder("西红柿鸡蛋面");
restaurant.serveFood("西红柿鸡蛋面");
restaurant.processPayment(10.0);
restaurant.cleanTable();
restaurant.handleComplaint();
}
}
测试结果如图
依赖倒置原则
- 高层模块不应该依赖低层模块,二者都应该依赖抽象
- 抽象不应该依赖细节,细节应该依赖抽象
字面拆解:四个字的含义
依赖:
- 指代码中模块/类之间的使用关系(如A类调用B类的方法)
- 例如:Service 依赖 Database 读写数据
倒置:
- 把传统的依赖方向"反转"过来
- 类比:
- 传统:高层模块→直接依赖→底层模块(如Service→MySQL)
- 倒置后:高层模块→依赖抽象←底层模块实现
Case
Bad Impl(违反原则)
// 低层模块 - 具体实现
class MySQLDatabase {
public void saveData(String data) {
System.out.println("使用MySQL保存数据: " + data);
}
}
// 高层模块 - 直接依赖低层模块
class DataService {
private MySQLDatabase database;
public DataService() {
this.database = new MySQLDatabase(); // 直接依赖具体实现
}
public void save(String data) {
database.saveData(data);
}
}
// 使用
public class BadExample {
public static void main(String[] args) {
DataService service = new DataService();
service.save("测试数据");
}
}
测试程序
public class Test {
public static void main(String[] args) {
DataService dataService = new DataService();
dataService.saveData("hello world");
}
}
结果图
问题:如果要改用Oracle数据库,必须修改DataService类。
Better Impl (遵守原则)
// 抽象接口 - 抽象不应该依赖细节
interface Database {
void save(String data);
}
// 低层模块 - 细节依赖抽象
class MySQLDatabase implements Database {
@Override
public void save(String data) {
System.out.println("使用MySQL保存数据: " + data);
}
}
class OracleDatabase implements Database {
@Override
public void save(String data) {
System.out.println("使用Oracle保存数据: " + data);
}
}
// 高层模块 - 依赖抽象
class DataService {
private Database database; // 依赖抽象
// 依赖注入(构造函数注入)
public DataService(Database database) {
this.database = database;
}
public void save(String data) {
database.save(data);
}
}
// 使用
public class GoodExample {
public static void main(String[] args) {
// 可以灵活切换数据库实现
Database mysql = new MySQLDatabase();
DataService service1 = new DataService(mysql);
service1.save("MySQL数据");
Database oracle = new OracleDatabase();
DataService service2 = new DataService(oracle);
service2.save("Oracle数据");
}
}
测试程序
public class Test {
public static void main(String[] args) {
// 可以灵活切换数据库实现
Database mysql = new MySQLDatabase();
DataService dataService = new DataService(mysql);
dataService.saveData("MySQL数据");
Database oracle = new OracleDatabase();
DataService dataService2 = new DataService(oracle);
dataService2.saveData("Oracle数据");
}
}
结果图
总结:
以上内容就是我对六大设计原则的重新理解,当然设计原则有人理解是六种,也有理解是七种的。不管理解是几种,设计模式和设计原则属于方法论的内容,是要帮助我们解决具体的业务问题的,当然需要具体问题具体对待。
如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家!!