第13章 面向对象设计

面向对象设计概述

面向对象设计(Object-Oriented Design,OOD)是一种软件开发方法,它将系统分解为相互交互的对象,每个对象代表系统中的一个实体,具有自己的状态和行为。

面向对象设计的基本原则

  1. 封装:将数据和行为捆绑在一起,形成一个独立的单元
  2. 继承:从现有类派生出新类,重用代码并扩展功能
  3. 多态:允许不同类型的对象对同一消息做出不同的响应
  4. 抽象:忽略不重要的细节,专注于本质特征

设计原则

SOLID原则

SOLID是一组面向对象设计的基本原则,有助于创建可维护、可扩展的软件。

单一职责原则(Single Responsibility Principle)

一个类应该只有一个引起它变化的原因。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 违反单一职责原则的示例
class User {
public:
void saveUser() { /* 保存用户到数据库 */ }
void sendEmail() { /* 发送邮件 */ }
};

// 遵循单一职责原则的示例
class User {
public:
// 用户相关属性和方法
};

class UserRepository {
public:
void saveUser(const User& user) { /* 保存用户到数据库 */ }
};

class EmailService {
public:
void sendEmail(const User& user, const std::string& message) { /* 发送邮件 */ }
};

开放封闭原则(Open-Closed Principle)

软件实体应该对扩展开放,对修改关闭。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 违反开放封闭原则的示例
class Shape {
public:
enum Type { CIRCLE, RECTANGLE };
Type type;
};

class AreaCalculator {
public:
double calculateArea(const Shape& shape) {
if (shape.type == Shape::CIRCLE) {
// 计算圆形面积
} else if (shape.type == Shape::RECTANGLE) {
// 计算矩形面积
}
return 0;
}
};

// 遵循开放封闭原则的示例
class Shape {
public:
virtual ~Shape() = default;
virtual double calculateArea() const = 0;
};

class Circle : public Shape {
public:
Circle(double radius) : radius(radius) {}
double calculateArea() const override {
return M_PI * radius * radius;
}
private:
double radius;
};

class Rectangle : public Shape {
public:
Rectangle(double width, double height) : width(width), height(height) {}
double calculateArea() const override {
return width * height;
}
private:
double width, height;
};

class AreaCalculator {
public:
double calculateArea(const Shape& shape) {
return shape.calculateArea();
}
};

里氏替换原则(Liskov Substitution Principle)

子类应该可以替换其父类,而不会影响程序的正确性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 违反里氏替换原则的示例
class Bird {
public:
virtual void fly() { /* 飞行 */ }
};

class Penguin : public Bird {
public:
void fly() override {
throw std::runtime_error("Penguins can't fly");
}
};

// 遵循里氏替换原则的示例
class Bird {
public:
virtual ~Bird() = default;
};

class FlyingBird : public Bird {
public:
virtual void fly() { /* 飞行 */ }
};

class Penguin : public Bird {
// 企鹅不会飞
};

接口隔离原则(Interface Segregation Principle)

客户端不应该依赖它不使用的接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 违反接口隔离原则的示例
class Worker {
public:
virtual void work() = 0;
virtual void eat() = 0;
};

class Robot : public Worker {
public:
void work() override { /* 工作 */ }
void eat() override { /* 机器人不需要吃饭 */ }
};

// 遵循接口隔离原则的示例
class Workable {
public:
virtual void work() = 0;
};

class Eatable {
public:
virtual void eat() = 0;
};

class Human : public Workable, public Eatable {
public:
void work() override { /* 工作 */ }
void eat() override { /* 吃饭 */ }
};

class Robot : public Workable {
public:
void work() override { /* 工作 */ }
};

依赖倒置原则(Dependency Inversion Principle)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 违反依赖倒置原则的示例
class LightBulb {
public:
void turnOn() { /* 打开灯泡 */ }
void turnOff() { /* 关闭灯泡 */ }
};

class Switch {
public:
Switch(LightBulb& bulb) : bulb(bulb) {}
void operate() { /* 操作开关 */ }
private:
LightBulb& bulb;
};

// 遵循依赖倒置原则的示例
class Switchable {
public:
virtual void turnOn() = 0;
virtual void turnOff() = 0;
};

class LightBulb : public Switchable {
public:
void turnOn() override { /* 打开灯泡 */ }
void turnOff() override { /* 关闭灯泡 */ }
};

class Fan : public Switchable {
public:
void turnOn() override { /* 打开风扇 */ }
void turnOff() override { /* 关闭风扇 */ }
};

class Switch {
public:
Switch(Switchable& device) : device(device) {}
void operate() { /* 操作开关 */ }
private:
Switchable& device;
};

设计模式

设计模式是在软件设计中反复出现的问题的解决方案。以下是一些常用的面向对象设计模式。

创建型模式

创建型模式专注于对象的创建过程。

单例模式(Singleton)

确保一个类只有一个实例,并提供一个全局访问点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Singleton {
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}

// 禁止拷贝和移动
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;

void doSomething() { /* 执行操作 */ }

private:
Singleton() { /* 私有构造函数 */ }
};

// 使用示例
void useSingleton() {
Singleton& instance = Singleton::getInstance();
instance.doSomething();
}

工厂方法模式(Factory Method)

定义一个用于创建对象的接口,让子类决定实例化哪一个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Product {
public:
virtual ~Product() = default;
virtual void use() = 0;
};

class ConcreteProductA : public Product {
public:
void use() override { /* 使用产品A */ }
};

class ConcreteProductB : public Product {
public:
void use() override { /* 使用产品B */ }
};

class Creator {
public:
virtual ~Creator() = default;
virtual std::unique_ptr<Product> createProduct() = 0;

void doSomething() {
auto product = createProduct();
product->use();
}
};

class ConcreteCreatorA : public Creator {
public:
std::unique_ptr<Product> createProduct() override {
return std::make_unique<ConcreteProductA>();
}
};

class ConcreteCreatorB : public Creator {
public:
std::unique_ptr<Product> createProduct() override {
return std::make_unique<ConcreteProductB>();
}
};

抽象工厂模式(Abstract Factory)

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class AbstractProductA {
public:
virtual ~AbstractProductA() = default;
virtual void use() = 0;
};

class ConcreteProductA1 : public AbstractProductA {
public:
void use() override { /* 使用产品A1 */ }
};

class ConcreteProductA2 : public AbstractProductA {
public:
void use() override { /* 使用产品A2 */ }
};

class AbstractProductB {
public:
virtual ~AbstractProductB() = default;
virtual void use() = 0;
};

class ConcreteProductB1 : public AbstractProductB {
public:
void use() override { /* 使用产品B1 */ }
};

class ConcreteProductB2 : public AbstractProductB {
public:
void use() override { /* 使用产品B2 */ }
};

class AbstractFactory {
public:
virtual ~AbstractFactory() = default;
virtual std::unique_ptr<AbstractProductA> createProductA() = 0;
virtual std::unique_ptr<AbstractProductB> createProductB() = 0;
};

class ConcreteFactory1 : public AbstractFactory {
public:
std::unique_ptr<AbstractProductA> createProductA() override {
return std::make_unique<ConcreteProductA1>();
}
std::unique_ptr<AbstractProductB> createProductB() override {
return std::make_unique<ConcreteProductB1>();
}
};

class ConcreteFactory2 : public AbstractFactory {
public:
std::unique_ptr<AbstractProductA> createProductA() override {
return std::make_unique<ConcreteProductA2>();
}
std::unique_ptr<AbstractProductB> createProductB() override {
return std::make_unique<ConcreteProductB2>();
}
};

结构型模式

结构型模式专注于类和对象的组合。

适配器模式(Adapter)

将一个类的接口转换成客户希望的另一个接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Target {
public:
virtual ~Target() = default;
virtual void request() = 0;
};

class Adaptee {
public:
void specificRequest() { /* 特定请求 */ }
};

class Adapter : public Target {
public:
Adapter(Adaptee& adaptee) : adaptee(adaptee) {}
void request() override {
adaptee.specificRequest();
}
private:
Adaptee& adaptee;
};

装饰器模式(Decorator)

动态地给一个对象添加一些额外的职责。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Component {
public:
virtual ~Component() = default;
virtual void operation() = 0;
};

class ConcreteComponent : public Component {
public:
void operation() override { /* 基本操作 */ }
};

class Decorator : public Component {
public:
Decorator(std::unique_ptr<Component> component) : component(std::move(component)) {}
void operation() override {
component->operation();
}
protected:
std::unique_ptr<Component> component;
};

class ConcreteDecoratorA : public Decorator {
public:
using Decorator::Decorator;
void operation() override {
Decorator::operation();
// 添加额外操作
}
};

class ConcreteDecoratorB : public Decorator {
public:
using Decorator::Decorator;
void operation() override {
Decorator::operation();
// 添加额外操作
}
};

组合模式(Composite)

将对象组合成树形结构以表示”部分-整体”的层次结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Component {
public:
virtual ~Component() = default;
virtual void operation() = 0;
virtual void add(std::unique_ptr<Component> component) {}
virtual void remove(Component* component) {}
virtual Component* getChild(int index) { return nullptr; }
};

class Leaf : public Component {
public:
void operation() override { /* 叶节点操作 */ }
};

class Composite : public Component {
public:
void operation() override {
for (auto& child : children) {
child->operation();
}
}

void add(std::unique_ptr<Component> component) override {
children.push_back(std::move(component));
}

void remove(Component* component) override {
// 移除子节点
}

Component* getChild(int index) override {
return children[index].get();
}

private:
std::vector<std::unique_ptr<Component>> children;
};

行为型模式

行为型模式专注于对象之间的通信。

观察者模式(Observer)

定义对象间的一种一对多依赖关系,当一个对象状态发生变化时,所有依赖它的对象都得到通知并被自动更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Observer {
public:
virtual ~Observer() = default;
virtual void update() = 0;
};

class Subject {
public:
virtual ~Subject() = default;
virtual void attach(std::shared_ptr<Observer> observer) {
observers.push_back(observer);
}

virtual void detach(Observer* observer) {
// 移除观察者
}

virtual void notify() {
for (const auto& observer : observers) {
observer->update();
}
}

private:
std::vector<std::shared_ptr<Observer>> observers;
};

class ConcreteSubject : public Subject {
public:
void setState(int state) {
this->state = state;
notify();
}

int getState() const {
return state;
}

private:
int state;
};

class ConcreteObserver : public Observer {
public:
ConcreteObserver(ConcreteSubject& subject) : subject(subject) {
this->subject.attach(std::shared_ptr<Observer>(this));
}

void update() override {
state = subject.getState();
// 处理更新
}

private:
ConcreteSubject& subject;
int state;
};

策略模式(Strategy)

定义一系列算法,把它们封装起来,并且使它们可相互替换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Strategy {
public:
virtual ~Strategy() = default;
virtual void algorithm() = 0;
};

class ConcreteStrategyA : public Strategy {
public:
void algorithm() override { /* 算法A */ }
};

class ConcreteStrategyB : public Strategy {
public:
void algorithm() override { /* 算法B */ }
};

class Context {
public:
void setStrategy(std::unique_ptr<Strategy> strategy) {
this->strategy = std::move(strategy);
}

void executeAlgorithm() {
strategy->algorithm();
}

private:
std::unique_ptr<Strategy> strategy;
};

命令模式(Command)

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
virtual void undo() = 0;
};

class Receiver {
public:
void action() { /* 执行操作 */ }
void reverseAction() { /* 撤销操作 */ }
};

class ConcreteCommand : public Command {
public:
ConcreteCommand(Receiver& receiver) : receiver(receiver) {}
void execute() override {
receiver.action();
}
void undo() override {
receiver.reverseAction();
}

private:
Receiver& receiver;
};

class Invoker {
public:
void setCommand(std::unique_ptr<Command> command) {
this->command = std::move(command);
}

void executeCommand() {
command->execute();
}

void undoCommand() {
command->undo();
}

private:
std::unique_ptr<Command> command;
};

面向对象设计最佳实践

1. 合理使用继承

  • 继承是一种”is-a”关系:派生类应该是基类的一种特殊类型
  • 避免过深的继承层次:继承层次应该控制在合理的范围内
  • 优先使用组合而非继承:当派生类和基类之间不是”is-a”关系时,应该使用组合

2. 设计良好的类

  • 单一职责:每个类应该只有一个职责
  • 高内聚:类的成员之间应该高度相关
  • 低耦合:类之间的依赖应该尽可能少
  • 接口简洁:只暴露必要的接口

3. 合理使用设计模式

  • 理解设计模式的适用场景:不同的设计模式适用于不同的场景
  • 不要过度使用设计模式:简单的问题应该用简单的解决方案
  • 灵活应用设计模式:根据具体情况调整设计模式

4. 代码组织

  • 模块化:将代码组织成逻辑模块
  • 命名规范:使用一致的命名规范
  • 注释:添加适当的注释
  • 代码风格:保持一致的代码风格

面向对象设计的挑战

1. 复杂性管理

  • 抽象层次:合理的抽象层次有助于管理复杂性
  • 模块化:将系统分解为模块化的组件
  • 文档:良好的文档有助于理解系统设计

2. 性能考虑

  • 继承与多态的开销:虚函数调用比普通函数调用慢
  • 内存开销:继承层次会增加对象的大小
  • 设计权衡:在设计和性能之间找到平衡点

3. 可测试性

  • 依赖注入:使用依赖注入提高可测试性
  • 接口隔离:使用接口隔离原则提高可测试性
  • 模拟对象:使用模拟对象进行单元测试

示例:面向对象设计的综合应用

图形编辑器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// 抽象图形类
class Shape {
public:
virtual ~Shape() = default;
virtual void draw() = 0;
virtual void move(int x, int y) = 0;
virtual std::unique_ptr<Shape> clone() = 0;
};

// 具体图形类
class Circle : public Shape {
public:
Circle(int x, int y, int radius) : x(x), y(y), radius(radius) {}

void draw() override {
std::cout << "Drawing circle at (" << x << ", " << y << ") with radius " << radius << std::endl;
}

void move(int dx, int dy) override {
x += dx;
y += dy;
}

std::unique_ptr<Shape> clone() override {
return std::make_unique<Circle>(x, y, radius);
}

private:
int x, y, radius;
};

class Rectangle : public Shape {
public:
Rectangle(int x, int y, int width, int height) : x(x), y(y), width(width), height(height) {}

void draw() override {
std::cout << "Drawing rectangle at (" << x << ", " << y << ") with width " << width << " and height " << height << std::endl;
}

void move(int dx, int dy) override {
x += dx;
y += dy;
}

std::unique_ptr<Shape> clone() override {
return std::make_unique<Rectangle>(x, y, width, height);
}

private:
int x, y, width, height;
};

// 图形工厂
class ShapeFactory {
public:
static std::unique_ptr<Shape> createShape(const std::string& type, int x, int y, int... params) {
if (type == "circle") {
return std::make_unique<Circle>(x, y, params[0]);
} else if (type == "rectangle") {
return std::make_unique<Rectangle>(x, y, params[0], params[1]);
}
return nullptr;
}
};

// 图形组合
class ShapeComposite : public Shape {
public:
void addShape(std::unique_ptr<Shape> shape) {
shapes.push_back(std::move(shape));
}

void removeShape(Shape* shape) {
// 移除图形
}

void draw() override {
for (const auto& shape : shapes) {
shape->draw();
}
}

void move(int dx, int dy) override {
for (auto& shape : shapes) {
shape->move(dx, dy);
}
}

std::unique_ptr<Shape> clone() override {
auto composite = std::make_unique<ShapeComposite>();
for (const auto& shape : shapes) {
composite->addShape(shape->clone());
}
return composite;
}

private:
std::vector<std::unique_ptr<Shape>> shapes;
};

// 图形编辑器
class GraphicsEditor {
public:
void addShape(std::unique_ptr<Shape> shape) {
shapes.push_back(std::move(shape));
}

void drawAll() {
for (const auto& shape : shapes) {
shape->draw();
}
}

void moveAll(int dx, int dy) {
for (auto& shape : shapes) {
shape->move(dx, dy);
}
}

private:
std::vector<std::unique_ptr<Shape>> shapes;
};

// 使用示例
void useGraphicsEditor() {
GraphicsEditor editor;

// 添加图形
editor.addShape(ShapeFactory::createShape("circle", 10, 10, 5));
editor.addShape(ShapeFactory::createShape("rectangle", 20, 20, 10, 8));

// 绘制所有图形
editor.drawAll();

// 移动所有图形
editor.moveAll(5, 5);

// 再次绘制所有图形
editor.drawAll();
}

总结

面向对象设计是一种强大的软件开发方法,它通过封装、继承、多态和抽象等概念,帮助开发者创建可维护、可扩展的软件系统。

SOLID原则是面向对象设计的基本原则,它们为创建高质量的软件提供了指导。设计模式是在软件设计中反复出现的问题的解决方案,它们可以帮助开发者更有效地解决常见的设计问题。

在实际开发中,应该根据具体情况灵活应用面向对象设计的原则和模式,在设计和性能之间找到平衡点,创建既优雅又高效的软件系统。