第13章 面向对象设计 面向对象设计概述 面向对象设计(Object-Oriented Design,OOD)是一种软件开发方法,它将系统分解为相互交互的对象,每个对象代表系统中的一个实体,具有自己的状态和行为。
面向对象设计的基本原则 封装 :将数据和行为捆绑在一起,形成一个独立的单元继承 :从现有类派生出新类,重用代码并扩展功能多态 :允许不同类型的对象对同一消息做出不同的响应抽象 :忽略不重要的细节,专注于本质特征设计原则 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 { } }; class ConcreteProductB : public Product {public : void use () override { } }; 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 { } }; class ConcreteProductA2 : public AbstractProductA {public : void use () override { } }; class AbstractProductB {public : virtual ~AbstractProductB () = default ; virtual void use () = 0 ; }; class ConcreteProductB1 : public AbstractProductB {public : void use () override { } }; class ConcreteProductB2 : public AbstractProductB {public : void use () override { } }; 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 { } }; class ConcreteStrategyB : public Strategy {public : void algorithm () override { } }; 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原则是面向对象设计的基本原则,它们为创建高质量的软件提供了指导。设计模式是在软件设计中反复出现的问题的解决方案,它们可以帮助开发者更有效地解决常见的设计问题。
在实际开发中,应该根据具体情况灵活应用面向对象设计的原则和模式,在设计和性能之间找到平衡点,创建既优雅又高效的软件系统。