面向对象设计模式原则-合成复用原则

优先使用组合而不是继承原则(CARP,Composite/Aggregate Reuse Principle)

注:继承和组合同时符合条件时,优先使用组合

合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:复用时要尽量使用组合/聚合关系(关联关系),少用继承。

如果使用继承,会导致父类的任何变换都可能影响到子类的行为。

如果使用对象组合,就降低了这种依赖关系。

组合/聚合关系和继承关系

在面向对象设计中,我们可以通过两种方法在不同的环境中复用已有的设计和实现,即通过组合/聚合关系或通过继承,但首先应该考虑使用组合/聚合,组合/聚合可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。

继承带来的问题
通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称“白箱”复用,如果基类发生改变,那么子类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性;而且继承只能在有限的环境中使用(如类没有声明为不能被继承)。

组合/聚合关系
由于组合或聚合关系可以将已有的对象(也可称为成员对象)纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能,这样做可以使得成员对象的内部实现细节对于新对象不可见,所以这种复用又称为“黑箱”复用,相对继承关系而言,其耦合度相对较低,成员对象的变化对新对象的影响不大,可以在新对象中根据实际需要有选择性地调用成员对象的操作;合成复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的其他对象。 
一般而言,如果两个类之间是“Has-A”的关系应使用组合或聚合,如果是“Is-A”关系可使用继承。”Is-A”是严格的分类学意义上的定义,意思是一个类是另一个类的”一种”;而”Has-A”则不同,它表示某一个角色具有某一项责任。

简单案例:

#define _CRT_NO_SECURE_WARNINGS
#include <iostream>
using namespace std;

/*继承和组合,优先使用组合
*人开车去兜风,车分很多种类,因此车作为一个抽象类
*/
class AbstractCar{
public:
	virtual void run() = 0;
};

class DaZhong : public AbstractCar{
public:
	virtual void run(){
		cout << "大众启动" << endl;
	}
};

class Benci : public AbstractCar{
public:
	virtual void run(){
		cout << "奔驰启动" << endl;
	}
};

class Person{
public:
	void setCar(AbstractCar* car){
		this->car = car;
	}

	void DouFeng(){
		this->car->run();
		cout << "外出兜风..............." << endl;

		if (this->car != NULL){
			delete this->car;
			this->car = NULL;
		}
	}
private:
	AbstractCar* car;
};

void test(){
	Person* per = new Person;
	per->setCar(new DaZhong);
	per->DouFeng();

	per->setCar(new Benci);
	per->DouFeng();

	delete per;
}

int main(void){
	test();
	return 0;
}
发布了161 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42067873/article/details/105499471