软件设计模式-面向对象设计原则
一、面向对象设计原则
- 如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一。
- 面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含在很多设计 模式中,它们是从许多设计方案中总结出的指导性原则。
- 原则的目的:高内聚,低耦合。
二、七大原则
名称 | 定义 |
---|---|
单一职责原则 | 类的职责单一,对外只提供一种功能,而引起类变 化的原因都应该只有一个。 |
开闭原则 | 类的改动通过增加代码实现,而不修改源码。 |
里氏代换原则 | 也就是虚拟机制:任何抽象类出现的地方,都可以用他的实现类进行替换。 |
依赖倒转原则 | 也就是针对接口编程:依赖于抽象,而不依赖于具体的实现 |
接口隔离原则 | 不强迫用户依赖他们不需要的接口方法。即:一个接口只实现一种功能 |
合成复用原则 | 对于继承和组合,优先使用组合。因为使用继承,父类的任何变化都可能影响到子类的行为 |
迪米特法则 | 一个对象对其它对象应尽可能少的了解,从而降低对象之间的耦合。例如:提供一个统一的接口,来实现模块之间的调用。 |
三、开闭原则案例
类的改动通过增加代码实现,而不修改源码。
以银行业务员为例,通过多态可实现开闭原则。
#include <iostream>
using namespace std;
//繁忙的银行业务员
class BankWorker
{
public:
//存钱
void save() { cout << "存钱" << endl; }
//转账
void transfer() { cout << "转账" << endl; }
//...
//随着业务的增加,类会越来越臃肿
};
//轻松的银行业务员
class RBankWorker
{
public:
virtual void doBusiness() = 0;
};
class saveBankWorker : public RBankWorker
{
public:
virtual void doBusiness(){
cout << "存钱" << endl;
}
};
class transferBankWorker : public RBankWorker
{
public:
virtual void doBusiness() {
cout << "转账" << endl;
}
};
//...
//例如,我们现在需要添加基金办理业务
class fundBankWorker : public RBankWorker
{
public:
virtual void doBusiness() {
cout << "基金办理" << endl;
}
};
int main(void)
{
RBankWorker* rw = NULL;
rw = new saveBankWorker;
rw->doBusiness();
delete rw;
rw = NULL;//务必添加,因为指针变量和指针指向的内存空间是两码事
rw = new transferBankWorker;
rw->doBusiness();
delete rw;
rw = NULL;
rw = new fundBankWorker;
rw->doBusiness();
delete rw;
rw = NULL;
return 0;
}
四、依赖倒转原则案例
针对接口编程:依赖于抽象,而不依赖于具体的实现
【传统】的过程式设计倾向于高层次依赖于低层次,抽象层依赖于具体实现层。
例如:仍以银行业务员为例
#include <iostream>
using namespace std;
//繁忙的银行业务员
class BankWorker
{
public:
//存钱
void save() { cout << "存钱" << endl; }
//转账
void transfer() { cout << "转账" << endl; }
//...
//随着业务的增加,类会越来越臃肿
};
//轻松的银行业务员
class RBankWorker
{
public:
virtual void doBusiness() = 0;
};
class saveBankWorker : public RBankWorker
{
public:
virtual void doBusiness(){
cout << "存钱" << endl;
}
};
class transferBankWorker : public RBankWorker
{
public:
virtual void doBusiness() {
cout << "转账" << endl;
}
};
//...
//例如,我们现在需要添加基金办理业务
class fundBankWorker : public RBankWorker
{
public:
virtual void doBusiness() {
cout << "基金办理" << endl;
}
};
void doBusiness(RBankWorker* rw)
{
rw->doBusiness();
}
void printAllWorker(RBankWorker* rw)
{
rw = new saveBankWorker;
rw->doBusiness();
delete rw;
rw = NULL;
rw = new transferBankWorker;
rw->doBusiness();
delete rw;
rw = NULL;
rw = new fundBankWorker;
rw->doBusiness();
delete rw;
rw = NULL;
}
int main(void)
{
RBankWorker* rw = NULL;
rw = new saveBankWorker;
doBusiness(rw);
delete rw;
rw = NULL;
printAllWorker(rw);
return 0;
}
这样自顶向下逐级依赖,底层模块、中间层模块和高层模块耦合度极高。一旦修改其中一个,很可能导致全面修改,非常麻烦。
而依赖倒转原则利用多态的特性,对中间层进行抽象依赖,这样底层和高层就解耦合了。
案例:组装电脑。电脑的硬盘,CPU,内存第三厂商均可以进行对接,但是电脑生产公司只是对外提供抽象中间层接口,第三方厂商想要加入只需要面向这个抽象类实现各自的实例就可以了。
#include <iostream>
using namespace std;
/* 中间层,抽象层 */
//硬盘
class HardDisk
{
public:
virtual void doWork() = 0;
};
//内存
class Memory
{
public:
virtual void doWork() = 0;
};
//CPU
class Cpu
{
public:
virtual void doWork() = 0;
};
/*
让Computer框架和具体的厂商解耦合
*/
/*高级架构层*/
class Computer
{
public:
Computer(HardDisk* hd, Memory* mem, Cpu* Cpu)
{
this->hd = hd;
this->mem = mem;
this->Cpu = Cpu;
}
//架构层并不关心是哪个厂商,只关心抽象层的业务
void doWork()
{
hd->doWork();
mem->doWork();
Cpu->doWork();
}
private:
HardDisk* hd;
Memory* mem;
Cpu* Cpu;
};
/*
实现层,具体的厂商
*/
//西数硬盘
class XiShuHardDisk : public HardDisk
{
public:
virtual void doWork()
{
cout << "西数硬盘正在运行中..." << endl;
}
};
//金士顿内存
class KingstonMemory : public Memory
{
public:
virtual void doWork()
{
cout << "金士顿内存正在运行中..." << endl;
}
};
//AMD CPU
class AmdCpu : public Cpu
{
public:
virtual void doWork()
{
cout << "AMD CPU正在运行中..." << endl;
}
};
int main()
{
XiShuHardDisk* xs = new XiShuHardDisk;
KingstonMemory* kingston = new KingstonMemory;
AmdCpu* amd = new AmdCpu;
Computer* myComputer = new Computer(xs, kingston, amd);
myComputer->doWork();
delete xs;
delete kingston;
delete amd;
delete myComputer;
return 0;
}
五、迪米特法则
不符合迪米特法则的方式
符合迪米特法则,不和陌生人说话
迪米特法则结合依赖倒转原则