学习目标
- 3.1 设计模式概述
- 3.2 软件可复用问题和面向对象设计原则
-
-
- 一、软件可复用问题
- 二、面向对象设计原则
-
- 1. 单一责任原则(Single Responsibility Principle, SRP)
- 2. 开放-封闭原则(Open-Closed Principle, OCP)
- 3. 里氏替换原则(Liskov Substitution Principle, LSP)
- 4. 依赖倒置原则(Dependency Inversion Principle, DIP)
- 5. 接口隔离原则(Interface Segregation Principle, ISP)
- 6. 迪米特法则(Least Knowledge Principle,LKP)
- 7. 合成/聚合复用原则(Composite/Aggregate Reuse Principle, CARP)
-
- 3.3 设计模式的应用
前面课程中已经学习了面向对象的三大特征,在后续的学习过程中对面向对象的认识会不断深入,不断提高运用面向对象思想解决问题的能力。(如果没有了解可以去我主页看看Java开发之框架基础技术第1-2章(2023版本IEDA)来学习)本章学习面向对象的一些高级应用一一设计模式。设计模式被广泛运用在java框架技术中,学习设计模式对于理解框架的工作原理会有所帮助。
学习方法
设计模式虽有很多种,但总是可以从解锅台、提高复用性这些方向来理解。首先要明确每种设计模式的使用场景,明确其要解决的问题,进而理解其解决该问题的思路。
3.1 设计模式概述
设计模式(Design Pattern)是人们在长期的软件开发中对一些经验的总结,是对某些特定问题经过实践检验的特定解决方法。就像兵法中的三十六计,总结了36种对于战争中某些场合的可行性计谋战术一一"围魏救赵"“声东击西”"走为上"等,可以说三十六计中的每一计都是一种模式。
- 创建型模式(Creational Patterns)
创建型模式主要用于对象的创建,它们通过隐藏对象的创建逻辑来提供更大的灵活性。
示例:单例模式(Singleton Pattern)
单例模式确保一个类仅有一个实例,并提供一个全局访问点。
public class Singleton {
// 私有静态变量,保存类的唯一实例
private static Singleton instance;
// 私有构造函数,防止外部通过new创建实例
private Singleton() {
}
// 提供一个全局的静态方法,返回唯一实例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
// 其他方法...
}
- 结构型模式(Structural Patterns)
结构型模式关注于类、接口和对象之间的组合关系,以创建更大的结构。
示例:适配器模式(Adapter Pattern)
适配器模式将一个类的接口转换成客户端期望的另一个接口形式,使类之间的接口不兼容问题可以通过一个中间类来解决。
// 目标接口
public interface Target {
void request();
}
// 需要适配的类
public class Adaptee {
public void specificRequest() {
// 具体请求
}
}
// 适配器类
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
- 行为型模式(Behavioral Patterns)
行为型模式主要关注对象之间的通信和交互方式。
示例:观察者模式(Observer Pattern)
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
// 抽象主题类
public abstract class Subject {
// 维护一个观察者列表
private List<Observer> observers = new ArrayList<>();
// 注册观察者
public void registerObserver(Observer o) {
observers.add(o);
}
// 移除观察者
public void removeObserver(Observer o) {
observers.remove(o);
}
// 通知所有观察者
protected void notifyObservers() {
for (Observer observer : observers) {
observer.update(this);
}
}
// 抽象的通知方法
public abstract void stateChanged();
}
// 抽象观察者类
public interface Observer {
void update(Subject subject);
}
// 具体实现
// ...(具体主题类和观察者类的实现)
注意
上述代码示例仅用于说明设计模式的基本思想和结构,并未包含完整的错误处理和优化逻辑。在实际应用中,您可能需要根据具体需求进行调整和完善。
设计模式的学习和应用需要结合具体的项目实践,通过不断尝试和反思来加深对设计模式的理解和应用能力。
3.2 软件可复用问题和面向对象设计原则
软件可复用问题和面向对象设计原则是两个紧密相连的概念。在软件开发中,可复用性是一个重要的目标,它旨在通过重用已有的软件组件来降低开发成本、提高开发效率和软件质量。面向对象设计原则则为实现软件的可复用性提供了指导和支持。
一、软件可复用问题
软件复用(Software Reuse)是使用已有的软件组件去实现或更新软件系统的过程。复用可以降低开发成本、缩短开发周期、提高软件质量,并促进软件标准化。然而,要实现软件的有效复用,需要解决以下几个关键问题:
- 组件的明确定义和标准化:可复用的组件需要具有明确的定义和标准化的接口,以便在不同的系统中被重用。
- 组件的独立性:组件之间应该尽可能少地相互依赖,以提高其独立性和可移植性。
- 组件的文档化和可理解性:良好的文档和易于理解的设计是复用组件的前提。
- 组件的测试和验证:复用前需要对组件进行充分的测试和验证,以确保其稳定性和可靠性。
二、面向对象设计原则
面向对象设计原则为软件的可复用性提供了指导和支持。以下是一些关键的面向对象设计原则:
1. 单一责任原则(Single Responsibility Principle, SRP)
一个类应该仅有一个引起它变化的原因。这有助于保持类的简洁和可维护性,从而提高其可复用性。
// 示例:一个类只负责一个功能
public class UserService {
// 负责用户注册的逻辑
public void registerUser(User user) {
// 注册逻辑...
}
// 如果有其他与用户相关的功能,应该放在其他类中
}
2. 开放-封闭原则(Open-Closed Principle, OCP)
软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着在添加新功能时,应该通过扩展现有系统来实现,而不是修改现有代码。这有助于保持系统的稳定性和可复用性。
// 示例:通过策略模式实现OCP
interface PaymentStrategy {
void pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(double amount) {
// 信用卡支付逻辑...
}
}
class CashPayment implements PaymentStrategy {
public void pay(double amount) {
// 现金支付逻辑...
}
}
class PaymentProcessor {
private PaymentStrategy strategy;
public PaymentProcessor(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void processPayment(double amount) {
strategy.pay(amount);
}
}
// 客户端代码
PaymentProcessor processor = new PaymentProcessor(new CreditCardPayment());
processor.processPayment(100.0);
3. 里氏替换原则(Liskov Substitution Principle, LSP)
子类型必须能够替换掉它们的基类型。这要求子类在继承基类时,必须保持与基类相同的行为特性,以确保在父类出现的地方可以使用子类来替换。
// 父类
class Rectangle {
protected double width;
protected double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
// 计算面积
public double area() {
return width * height;
}
}
// 子类,尝试遵循里氏替换原则
class Square extends Rectangle {
// 由于Square的特殊性,这里不能直接使用父类的构造器
// 因为Square的宽和高必须相等
public Square(double side) {
super(side, side); // 调用父类构造器,强制宽和高相等
}
// 尝试修改面积方法(但这样做可能违反里氏替换原则)
// @Override
// public double area() {
// return width * width; // 直接使用width的平方,但这会破坏里氏替换原则
// }
// 为了保持里氏替换原则,我们不覆盖area方法
// 而是添加一个新的方法来计算正方形的特定属性(比如周长)
public double perimeter(<

最低0.47元/天 解锁文章


被折叠的 条评论
为什么被折叠?



