c++编程风格----读书笔记(1)

一、抽象

    在软件开发中,抽象处于一种中心地位,而类则是C++中最重要的抽象机制。类描述的是所有从这个类实例化出来的对象的共同属性,并且刻画了这些对象的共同行为。在C++设计中,正确识别抽象是一个很关键的步骤。如果想获得高质量的抽象,那么程序员就必须要充分地理解程序中的各种对象的内在属性。

1、编程风格示例,如下程序:

#include "stdafx.h"
#include "iostream"

enum CARD	{ CDROM, TAPE, NEWWORK };
enum MONITOR{ MONO, COLOR };

class Card
{
public:
	virtual int	 Price() = 0;
	virtual char *Name() = 0;
	virtual int	 Rebate();
};

class NetWork : public Card
{
public:
	int	 Price();
	char *Name();
};

class CDRom : public Card
{
public:
	int	 Price();
	char *Name();
	int  Rebate();
};

class Tape : public Card
{
public:
	int	 Price();
	char *Name();
};

class Monitor
{
public:
	virtual int	 Price() = 0;
	virtual char *Name() = 0;
};

class Color : public Monitor
{
public:
	int	 Price();
	char *Name();
};

class Monochrome : public Monitor
{
public:
	int	 Price();
	char *Name();
};

int Card::Rebate()		 { return 45; }

int	 NetWork::Price()	 { return 600;       }
char *NetWork::Name()	 { return "NetWork"; }

int CDRom::Price()		 { return 1500;    }
char *CDRom::Name()		 { return "CDRom"; }
int CDRom::Rebate()		 { return 135;     }

int Tape::Price()		 { return 1000;   }
char *Tape::Name()		 { return "Tape"; }

int Color::Price()		 { return 1500;	   }
char *Color::Name()		 { return "Color"; }

int Monochrome::Price()	 { return 500;	  }
char *Monochrome::Name() { return "Mono"; }

class Computer
{
public:
	Computer(CARD, MONITOR);
	~Computer();

public:
	int NetPrice();
	void Print();
private:
	Card	*card;
	Monitor *mon;
};

Computer::Computer(CARD c, MONITOR m)
{
	switch (c)
	{
	case CDROM:
		card = new CDRom();
		break;
	case TAPE:
		card = new Tape();
		break;
	case NEWWORK:
		card = new NetWork();
		break;
	default:
		break;
	}
	switch (m)
	{
	case MONO:
		mon = new Monochrome();
		break;
	case COLOR:
		mon = new Color();
		break;
	default:
		break;
	}
}

Computer::~Computer()
{
	if (card)
	{
		delete card;
		card = NULL;
	}
	if (mon)
	{
		delete mon;
		mon = NULL;
	}
}

int Computer::NetPrice()
{
	return mon->Price() + card->Price() - card->Rebate();
}

void Computer::Print()
{
	std::cout << card->Name() << "   " << mon->Name() << " , " << 
		"net Price = " << NetPrice() << std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	Computer mn(NEWWORK, MONO);
	Computer mc(CDROM,	 MONO);
	Computer mt(TAPE,	 MONO);
	Computer cn(NEWWORK, COLOR);
	Computer cc(CDROM,	 COLOR);
	Computer ct(TAPE,	 COLOR);

	mn.Print();
	mc.Print();
	mt.Print();
	cn.Print();
	cc.Print();
	ct.Print();

	return 0;
}

想一想这里是否有必要写得这么冗长和复杂?这个程序是不是一定需要8个类,并且其中有7个类含有虚函数,才能解决问题?

2、找出上面程序中共同的抽象

    CardMonitor这两个类的接口是相似的:它们都含有纯虚函数Pirce()和Name()。不同的地方在于Card类中海油一个虚函数Rebate()。所以可以把这两个类再次抽象出来一个Component类,还有这段代码:

int Computer::NetPrice()
{
	return mon->Price() + card->Price() - card->Rebate();
}

不应该显示地依赖于组件是否存在折扣,而应该对每种组件进行统一处理,这里实际上隐含了另一个抽象,如果将NetPrice也作为一个成员函数添加到Component类中,那么在函数Component::NetPrice()中只需调用Component的其他成员函数即可(也就是将共同的抽象提取出来并放到基类中)

3、来看看其他的如CDRomNetWork之间的区别,而他们只在于各自虚函数返回的值时不同。在实际工作中,程序并不会为每个需要创建的对象提供一个不同的类,而是用一个类来表示一组对象(也就是一个类应该能够描述一组对象)

4、最初编写这个程序的人员陷入了一个常见的思维陷阱,他认为,在用C++来进行程序设计时,继承和虚函数是唯一的方法。于是,他在程序中过度地使用了继承,从而导致某些类的声明过于具体,甚至只能描述一种对象。如果在不同的对象之间有不同的行为,那么继承和多态是很有用的工具。然而,在本程序中,对象之间的不同之处在于他们的属性,而并非行为(如果派生类之间的区别在于属性,则用数据成员来表示;如果在于行为,则用虚函数来表示)

5、引入继承

    经过修改,我们现在的程序只有Component,但是程序需要将扩展卡和显示器区分开来,并且他们只是折扣不一样,所以加入继承,为两者提供不同的构造函数,从而提供合适的特化

    通常,如果派生类是基类的特化,存在着派生类是“一种基类对象”这种关系时,可以考虑将派生类之间的不同之处局限在初始化过程中

6、去掉枚举

    CardMonitor是两种截然不同的类型。如果将Computer::Computer的参数改为指向对象的指针,那么就可以去掉枚举和switch语句。


7、来看看经过修改的程序:

#include "stdafx.h"
#include "iostream"

class Component
{
public:
	Component(int price, char *name, int rebate)
		:price_(price), name_(name), rebate_(rebate)
	{

	}
public:
	int	 Price()  { return price_; }
	char *Name()  { return name_;  }
	int Rebate()  { return rebate_;}
	int NetPrice(){ return (rebate_ - rebate_); }
private:
	int price_;
	char *name_;
	int rebate_;
};

class Card : public Component
{
public:
	Card(int price, char *name, int rebate = 45)
		: Component(price, name, rebate)
	{

	}
};

class Monitor : public Component
{
public:
	Monitor(int price, char *name, int rebate = 0)
		: Component(price, name, rebate)
	{

	}
};

class Computer
{
public:
	Computer(Card *card, Monitor *monitor);

public:
	int NetPrice();
	void Print();
private:
	Card	*card_;
	Monitor *monitor_;
};

Computer::Computer(Card *card, Monitor *monitor)
{
	card_ = card;
	monitor_ = monitor;
}

int Computer::NetPrice()
{
	return (card_->Rebate() + monitor_->Rebate());
}

void Computer::Print()
{
	std::cout << card_->Name() << "   " << monitor_->Name() << " , " << 
		"net price = " << NetPrice() << std::endl;
}

void InitSoming()
{
	Card NetWork(600, "NetWork");
	Card CDRom(600, "CDROM", 135);
	Card Tape(600, "TAPE");

	Monitor Color(1500, "Color");
	Monitor Mono(500, "Mono");

	Computer mn(&NetWork,&Mono);
	Computer mc(&CDRom,	 &Mono);
	Computer mt(&Tape,	 &Mono);
	Computer cn(&NetWork,&Color);
	Computer cc(&CDRom,	 &Color);
	Computer ct(&Tape,	 &Color);

	mn.Print();
	mc.Print();
	mt.Print();
	cn.Print();
	cc.Print();
	ct.Print();
}

int _tmain(int argc, _TCHAR* argv[])
{
	InitSoming();

	return 0;
}


  • 21
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值