Favor composition over inheritance

        Composition is also known as HAS-A relation and inheritance is also known asIS-A relation. And HAS-A can be better than an IS-A relationship.So make it a habit of always preferring composition over inheritance.

        http://www.artima.com/designtechniques/compoinh.html介绍了java的这两种relate class的方式。

一、inheritance and composition

1)inheritance的C++代码

class Fruit
{
//
};

class Apple: public Fruit
{
//
};

2)composition的C++代码

class Fruit
{
//
};
class Banana
{
	Banana() { fruit = new Fruit; }
private:
	Fruit *fruit;
};

二、Dynamic binding, polymorphism

         Dynamic binding occurs when a pointer or reference is associated with a member function based on thedynamic type of the object.

The dynamic type of an object is the type of the object actually pointed or referred to rather than the static type of its pointer or reference.

The member function that is dynamically bound must override a virtual function declared in a direct or indirect base class.

Since dynamic binding occurs at run time, it is also called run time binding.

        Polymorphism allows multiple implementations of a member function to be defined, each implementing different behavior.

         以下是用动态绑定实现的代码。可以看到,输出的Fruit的属性是由指针fruit指向的对象决定的。

         动态绑定的优点是,当需要输出另外一种fruit的属性,如watermelon,只需要添加watermelon类,并使fruit指向一个watermelon对象即可,其他部分的代码无需改动。

#include <iostream>

using namespace std;

class Fruit
{
public:
	virtual void outputAttr(){ cout << "I am fruit" << endl; }
	virtual ~Fruit(){};
};

class Apple: public Fruit
{
public:
	void outputAttr() { cout << "I am fruit and I am red" << endl; }
	virtual ~Apple(){};
};

class Banana: public Fruit
{
public:
	void outputAttr() { cout << "I am fruit and I am yellow" << endl; }
	virtual ~Banana(){};
};

void outputFruitAttr(Fruit *fruit)
{
	fruit->outputAttr();
}

int main()
{
	Fruit *fruit;
	fruit = new Apple;
	outputFruitAttr(fruit);
	fruit = new Banana;
	outputFruitAttr(fruit);
}
输出:

I am fruit and I am red
I am fruit and I am yellow

        以上是使用inheritance的方式,使用composition实现类似功能的代码如下:

#include <iostream>

using namespace std;

class Fruit
{
public:
	virtual void outputAttr(){ cout << "I am fruit" << endl; }
	virtual ~Fruit(){};
};

class Apple
{
public:
	Apple() { fruit = new Fruit; }
	void outputAttr() { fruit->outputAttr(); cout << "I am red" << endl; }
	virtual ~Apple(){ delete fruit; };
private:
	Fruit *fruit;
};

class Banana
{
public:
	Banana() { fruit = new Fruit; }
	void outputAttr() { fruit->outputAttr(); cout << "I am yellow" << endl; }
	virtual ~Banana(){ delete fruit; };
private:
	Fruit *fruit;
};

int main()
{
	Apple *apple;
	apple = new Apple;
	apple->outputAttr();

	Banana *banana;
	banana = new Banana;
	banana->outputAttr();
}

三、修改类Fruit的接口对main函数(接口/类的使用者)的影响

         假设定义Fruit类的programmer修改它的成员函数outputAttr(),使该成员函数有参数,如该水果的种类。

         用inheritance实现的代码,需要修改main()中的函数调用才能编译通过。代码如下:

class Fruit
{
public:
	virtual void outputAttr(int species)
	{
		cout << "I am fruit. " << "I have " << species << " species" << endl;
	}
	virtual ~Fruit(){};
};

class Apple: public Fruit
{
public:
	void outputAttr()
	{
		cout << "I am fruit and I am red. ";
	}
	virtual ~Apple(){};
};

class Banana: public Fruit
{
public:
	void outputAttr()
	{
		cout << "I am fruit and I am yellow. ";
	}
	virtual ~Banana(){};
};

void outputFruitAttr(Fruit *fruit, int species)
{
	fruit->outputAttr(species);
}

int main()
{
	Fruit *fruit;
	fruit = new Apple;
	int appleSpecies = 2;
	outputFruitAttr(fruit, appleSpecies);

	fruit = new Banana;
	int bananaSpeices = 3;
	outputFruitAttr(fruit, bananaSpeices);
}

         用过composition是实现的代码,则无需修改main()中的函数调用(但需修改Apple类, Banana类的重载接口)。代码如下:

class Fruit
{
public:
	virtual void outputAttr(int species)
	{
		cout << "I am fruit. " << "I have " << species << " species" << endl;
	}
	virtual ~Fruit(){};
};

class Apple
{
public:
	Apple():species(2) { fruit = new Fruit; }
	void outputAttr() { fruit->outputAttr(species); cout << "I am red" << endl; }
	virtual ~Apple(){delete fruit;};
private:
	Fruit *fruit;
	int species;
};

class Banana
{
public:
	Banana():species(3) { fruit = new Fruit; }
	void outputAttr() { fruit->outputAttr(species); cout << "I am yellow" << endl; }
	virtual ~Banana(){delete fruit;};
private:
	Fruit *fruit;
	int species;
};

int main()
{
	Apple *apple;
	apple = new Apple;
	apple->outputAttr();

	Banana *banana;
	banana = new Banana;
	banana->outputAttr();
}

         可知,用composition实现的话,对越往下层的类影响更小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值