当前位置: 首页 > news >正文

面向对象与设计模式第一课:深入理解OOP

第三章:面向对象与设计模式

第一课:深入理解OOP

面向对象编程(OOP)是一种编程范式,它将程序结构视为由对象组成,促进了代码的重用性和可维护性。在这一课中,我们将深入分析OOP的四个基本特性:封装、继承、多态和抽象,并提供相应的示例与实践。

1. OOP基本特性
1.1 封装

封装是OOP的核心概念之一,它指的是将对象的状态(属性)和行为(方法)组合在一起,同时隐藏内部实现细节,只暴露必要的接口。这使得对象可以保护自己的数据不被外部干扰,从而提高了代码的安全性和稳定性。

示例

class BankAccount {
private:double balance; // 账户余额public:BankAccount(double initial_balance) : balance(initial_balance) {}void deposit(double amount) {if (amount > 0) {balance += amount;}}void withdraw(double amount) {if (amount > 0 && amount <= balance) {balance -= amount;}}double getBalance() const {return balance;}
};

在上面的示例中,balance属性被声明为私有(private),外部代码无法直接访问。只有通过公共方法(depositwithdrawgetBalance),才能修改或获取余额。

1.2 继承

继承允许一个类从另一个类派生,从而获得其属性和行为。这种机制支持代码重用和逻辑结构的组织,使得程序设计更加灵活。

示例

class SavingsAccount : public BankAccount {
private:double interestRate; // 利率public:SavingsAccount(double initial_balance, double rate): BankAccount(initial_balance), interestRate(rate) {}void applyInterest() {deposit(getBalance() * interestRate);}
};

在这个例子中,SavingsAccount类继承自BankAccount类,得到了其所有的属性和方法,并增加了一个新的方法applyInterest,用于计算利息。

1.3 多态

多态允许对象以不同的形式表现。这意味着可以使用同一接口来处理不同类型的对象。这通常通过虚函数实现,使得程序可以在运行时选择调用哪个函数。

示例

class Shape {
public:virtual void draw() const = 0; // 纯虚函数
};class Circle : public Shape {
public:void draw() const override {// 画圆的逻辑}
};class Rectangle : public Shape {
public:void draw() const override {// 画矩形的逻辑}
};void render(const Shape& shape) {shape.draw(); // 动态调用
}

在这个示例中,Shape是一个基类,定义了一个纯虚函数drawCircleRectangle类实现了这个函数。通过传递Shape引用,render函数能够根据实际对象类型动态调用相应的draw方法。

1.4 抽象

抽象是指通过提取对象的共同特征来创建类。抽象类通常包含纯虚函数,无法实例化。它们提供了一个模板,其他类可以从中继承并实现特定的功能。

示例

class Animal {
public:virtual void makeSound() const = 0; // 抽象方法
};class Dog : public Animal {
public:void makeSound() const override {// 狗叫的逻辑}
};class Cat : public Animal {
public:void makeSound() const override {// 猫叫的逻辑}
};

在这个例子中,Animal是一个抽象类,定义了一个纯虚函数makeSoundDogCat类实现了这个函数,表示它们各自的叫声。

2. 类的设计原则与实际案例

设计原则帮助开发者编写可维护、可扩展和可重用的代码。以下是几个常用的设计原则:

2.1 单一职责原则(SRP)

一个类应该只有一个单一的职责,所有的功能都应该围绕这个职责展开。这可以减少类的复杂性,便于维护和修改。

示例

class User {
public:void login() {// 登录逻辑}
};class UserNotifier {
public:void notifyUser() {// 通知用户逻辑}
};

在这个示例中,User类负责用户登录,而UserNotifier类负责用户通知。两个类各司其职,符合单一职责原则。

2.2 开放封闭原则(OCP)

软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。这意味着可以通过添加新代码而不是修改现有代码来实现新功能。

示例

class Shape {
public:virtual double area() const = 0; // 纯虚函数
};class Circle : public Shape {
public:double area() const override {// 计算圆的面积}
};class Rectangle : public Shape {
public:double area() const override {// 计算矩形的面积}
};// 新增多边形类
class Polygon : public Shape {
public:double area() const override {// 计算多边形的面积}
};

在这个例子中,新增的Polygon类并没有修改现有的代码,而是通过继承Shape类实现新的功能,符合开放封闭原则。

2.3 里氏替换原则(LSP)

子类对象应该能够替换父类对象,而不会影响程序的正确性。这意味着子类必须符合父类的约定。

示例

void drawShape(const Shape& shape) {shape.draw(); // 可以接受任何形状的子类
}

确保CircleRectangle等子类都能正确执行父类的方法,不会引入错误。

2.4 接口隔离原则(ISP)

不应强迫客户依赖于他们不使用的接口。接口应该细化为特定的、功能单一的接口。

示例

class IShape {
public:virtual void draw() const = 0;
};class IColor {
public:virtual void fill() const = 0;
};class Circle : public IShape, public IColor {
public:void draw() const override {// 画圆的逻辑}void fill() const override {// 填充圆的逻辑}
};

在这个例子中,IShapeIColor接口分别定义了不同的功能,避免了客户不必要的依赖。

2.5 依赖倒置原则(DIP)

高层模块不应该依赖低层模块,二者都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。

示例

class Notification {
public:virtual void send() = 0; // 抽象通知
};class EmailNotification : public Notification {
public:void send() override {// 发送电子邮件逻辑}
};class SmsNotification : public Notification {
public:void send() override {// 发送短信逻辑}
};class User {Notification* notifier;public:User(Notification* n) : notifier(n) {}void notify() {notifier->send(); // 使用抽象发送通知}
};

在这个示例中,User类依赖于Notification接口而不是具体的通知实现,从而实现了依赖倒置原则。

3. 项目实践

在实际项目中,运用OOP的特性和设计原则是非常重要的。下面是一个基于OOP的简单项目示例。

3.1 项目背景

我们要创建一个简单的图形编辑器,能够支持绘制多种形状并计算其面积。通过OOP的特性,我们可以设计出灵活且易于扩展的结构。

3.2 类的设计
  • Shape类作为抽象基类,定义绘制和计算面积的方法。
  • 具体的形状类(如CircleRectangle)继承自Shape并实现相关方法。
  • ShapeManager类负责管理所有形状,提供添加、删除和遍历功能。
3.3 代码示例
#include <iostream>
#include <vector>
#include <memory>class Shape {
public:virtual void draw() const = 0;virtual double area() const = 0;virtual ~Shape() = default; // 虚析构函数
};class Circle : public Shape {
private:double radius;public:Circle(double r) : radius(r) {}void draw() const override {std::cout << "Drawing Circle with radius: " << radius << std::endl;}double area() const override {return 3.14 * radius * radius;}
};class Rectangle : public Shape {
private:double width, height;public:Rectangle(double w, double h) : width(w), height(h) {}void draw() const override {std::cout << "Drawing Rectangle with width: " << width << " and height: " << height << std::endl;}double area() const override {return width * height;}
};class ShapeManager {
private:std::vector<std::shared_ptr<Shape>> shapes;public:void addShape(std::shared_ptr<Shape> shape) {shapes.push_back(shape);}void drawAll() const {for (const auto& shape : shapes) {shape->draw();}}void calculateTotalArea() const {double totalArea = 0;for (const auto& shape : shapes) {totalArea += shape->area();}std::cout << "Total Area: " << totalArea << std::endl;}
};int main() {ShapeManager manager;manager.addShape(std::make_shared<Circle>(5.0));manager.addShape(std::make_shared<Rectangle>(4.0, 6.0));manager.drawAll();manager.calculateTotalArea();return 0;
}

在这个简单的图形编辑器项目中,我们通过OOP的特性和设计原则,实现了一个可扩展的框架。将来可以很方便地添加新的形状类,而无需修改现有代码。

总结

本课深入探讨了面向对象编程的基本特性,包括封装、继承、多态和抽象,以及如何应用这些特性设计出符合OOP原则的类。在实际开发中,遵循设计原则有助于编写可维护、可扩展的代码。通过简单的项目实例,我们展示了OOP在实际中的应用,帮助初级到中级程序员更好地理解和应用OOP的理念。


http://www.mrgr.cn/news/55130.html

相关文章:

  • CRC-校验
  • Docker 入门 - 拉取/创建镜像 + 运行和管理容器
  • JAVA课设-图书指引系统(前后端分离)
  • Nginx(六)
  • 【ios】在 SwiftUI 中实现可随时调用的加载框
  • 枚举的使用举例说明
  • 机器学习——量子机器学习(Quantum Machine Learning)
  • Js中,const为什么常用来定义函数?
  • 基于大模型的招聘智能体:从创意到MVP
  • 【RoadRunner】自动驾驶模拟3D场景构建 | 自定义交叉口工具详解
  • Android SELinux——添加策略实例(十五)
  • 组装电脑主板配置全解析:从入门到精通
  • SSDF攻击及防御PPT及讲稿
  • 【漏洞复现】华望云 会议管理平台 deptactionlist 后台SQL注入漏洞
  • 基于单片机的多功能鱼缸控制系统设计
  • Java数组的特性与实现、与其他语言的区别、多维数组的遍历、底层实现及其内存管理
  • YoloV9改进策略:归一化改进| ContraNormYoloV8中的创新应用(全网首发)
  • Java反射深入学习
  • c语言字符串函数strstr,strtok,strerror
  • AIGC实战——世界模型(World Model)
  • MiniConda 的安装与使用
  • 【学术会议投稿】Java Web开发实战:从零到一构建动态网站
  • 【学术会议投稿】机器学习框架终极指南:PyTorch vs TensorFlow vs Keras vs Scikit-learn
  • Anomalib 1.x 系列之二:自定义数据
  • 手动部署Java项目、nginx前端和mysql数据库到centos虚拟机
  • 简单的界面用于控制自动点击器