最近在拜读《重构:改善既有代码的设计》(第二版),与GoF的《设计模式》一同被誉为软件工程师的两本圣经。过程中,由于书中代码是由JavaScript所写,对理解书中精髓和手法有很大的影响。尤其是对于像我这样从未接触过JavaScript的同学来说。故而想通过C++来改写书中案例,一方面为了自己更好地理解,另一方面为志同道合的C++爱好者提供一份参考。
起点
假设有如下需求:有一个戏剧演出团
- 剧团有剧目类型:悲剧(tragedy)和喜剧(comedy)
- 客户选择演出剧目
- 剧团根据观众人数(audience)和剧目类型收费
- 收费需要根据到场观众给出积分用于获取折扣。
设计剧目类
enum PlayCode {
TRAGEDY = 0,
COMEDY = 1
};
class Play {
public:
Play() {
}
Play(const string& _playName, int _playCode) {
name = _playName;
playCode = _playCode;
}
string GetPerfName() {
return name; }
int GetPerfCode() {
return playCode; }
private:
string name;
int playCode;
};
设计演出类
class Performance {
public:
Performance() {
}
Performance(const Play& _playId, int _audience) {
playId = _playId;
audience = _audience;
}
int GetAudience() {
return audience; }
Play GetPlayId() {
return playId; }
private:
Play playId;
int audience;
};
设计客户类
class Customer {
public:
Customer(string _custom) {
name = _custom;
}
void AddPerformance(const Performance& perf) {
performances.emplace_back(perf);
}
string GetName() {
return name; }
string statement() {
double totalAmount = 0;
int volumeCredits = 0;
string result = "Statement for " + name + "\n";
for (auto& perf : performances) {
double thisAmount = 0;
switch (perf.GetPlayId().GetPerfCode()) {
case PlayCode::TRAGEDY: {
thisAmount = 40000;
if (perf.GetAudience() > 30) {
thisAmount += 1000 * (perf.GetAudience() - 30);
}
break;
}
case PlayCode::COMEDY: {
thisAmount = 30000;
if (perf.GetAudience() > 20) {
thisAmount += 10000 + 500 * (perf.GetAudience() - 20);
}
thisAmount += 300 * perf.GetAudience();
break;
}
default:
cout << "unknown type " << perf.GetPlayId().GetPerfCode() << endl;
}
// add volume credits
volumeCredits += max(perf.GetAudience() - 30, 0);
// add extra credit for every ten comedy attendees
if (perf.GetPlayId().GetPerfCode() == PlayCode::COMEDY) volumeCredits += (perf.GetAudience() / 5);
result += "\t" + perf.GetPlayId().GetPerfName() + "\t" + to_string(thisAmount / 100) +
"(" + to_string(perf.GetAudience()) + " seats)\n";
totalAmount += thisAmount;
}
result += "Amount owed is " + to_string(totalAmount / 100) + "\n";
result += "You earned " + to_string(volumeCredits)