OOP第十六章:面向对象的软件开发

软件开发过程的演变

Waterfall 过程

分析、设计、编码、部署,序列从分析到部署,都朝一个方向运行

面向对象的程序设计

OOP有助于设计过程,因为程序中的对象与用户世界中的对象相对应

统一软件开发过程:被称为用力驱动的进程

启动:确定了项目的总体范围和可行性,这一阶段以管理层批准继续进行而结束

细化:设计了系统的基本体系结构,这里的需求决定里用户的需求

构建:包括软件的设计和代码的实际编写

过渡:系统被移交给用户进行测试和部署
 

用例建模:

用例建模允许软件系统的未来用户尽可能多地输入其设计

用例方法中有两个主要的实体:行动者和用例

场景:

一个用例通常由许多场景组成。用例指定了一个目标,而场景表示在试图达到该目标时的特定结果

例子:书店职员查询商店的计算机系统中特定书的位置,有几种可能的结果或情况

1、这本书在商店里,电脑显示了它的书架位置;

2、这本书已经缺货了,但该系统让客户有机会从出版商那里订购它;

3、这本书不仅缺货,也已经绝版。

 在正式的开发过程中,每个场景都将有自己的文档,并详细描述该场景中的所有事件。

用例图:UML指定如何绘制用例,用“——”将执行者和用例链接起来,通常不显示方向,但是箭头可以用来显示是谁启动了这个用例。

用例描述:用例图没有个别的详细描述,所以它们必须单独提供,用例图和用例描述主要用于系统的初始化设计中,以帮助用户和开发人员之间的通信

程序设计问题

承租人名单
租金收入记录
费用记录
年度总结

LANDLORD项目细化阶段

这个小组从确定角色的身份开始。谁将向程序中输入信息?谁会请求信息?还有其他人会与这个程序互动吗?该程序会与其他程序或系统进行交互吗?

房东需要做的事:

启动程序
向用户列表中添加一个新用户
向租金记录中输入一笔租金
将费用输入到费用记录中
显示租户列表
显示租金记录
显示费用记录
显示年度汇总

 用例说明:

启动:当它第一次启动时,程序应该显示一个屏幕,用户可以从中选择要执行的任务。可以被称为用户界面屏幕

添加新用户:该程序显示租户输入屏幕,提示用户输入新租户的姓名和公寓号码。然后,它会将此信息放在租户列表中的一个新行中。这个列表会按公寓号码自动排序。

输入租金支付:“租金输入”屏幕会提示用户输入租户的姓名/租金所在的月份和所收到的租金金额。该程序会在租户列表中查找租户的名称,并使用相应的公寓号码来访问租金记录。如果这是租户第一次支付租金,则会在租金记录中创建一个新的行,并插入相应月份的租金金额。否则,租金将被插入到现有的行中。

输入费用支付:费用输入屏幕提示用户输入收款人、所支付的金额、付款的日期和月份,以及预算类别。然后,程序将创建一个包含此信息的新行,并将其插入到费用记录中。

显示租户列表:该程序显示租户列表,其中每一行包含一个公寓号码和租户的姓名。

显示租金记录:该程序显示了租金记录,其中每一行包含一个公寓号码和每月支付的金额

显示费用记录:该程序显示费用记录,其中每月包含月、日期、收款人、金额和预算类别

显示年度汇总:

今年迄今为止所支付的所有租金的总和
每个预算类别的总费用清单
所得余额(本年度至今的损益)

场景:

假设用户试图将第二个租户进入已被占用的公寓

假设用户试图为一个不存在的租户输入租金支付

UML活动图:

UML活动图可用于建模用例。这种图显示了从一个活动到另一个活动的控制流程

活动以菱形的轮廓显示,连接这些活动的线表示从一个活动到另一个活动的转换。分支显示为菱形,有一个进入和两个或多个输出的过渡

初始状态和结束状态都用实心圆表示。

从用例到类

开发将在该程序中使用的类:

1、查看用例描述中的名词,我们希望程序中的对象与现实世界中的对象相呼应,而这些名词代表了由用户指定的真是世界中的实体,它们是类的候选词,但并不是所有的名词都是好的类。一旦有了一些候选类,我们就可以通过检查用例描述中的动词来开始理解它们是如何交互的,在许多情况下,动词翻译为从一个对象发送到另一个对象的消息,或类之间的其他关联。

列出名词:一下是从用例描述中挑选出的名词列表:

用户界面屏幕 √租户行租金金额收款人费用记录√
租户√租户列√租金记录√费用金额年度总结√
租户输入屏幕√租金支付租金行√日期租金总额
租户名称租金输入屏幕√费用支付√预算类别按类别划分的总费用
公寓编号月份费用输入屏幕√支出行(费用行)平衡

细化列表: 我们已经列出看各种记录中的行:租金行、租户行、费用行

但是租户记录中的每一行只保存一个租户数据,而费用记录中的每一行只保存一个费用的数据。现在已经有了针对租户和费用的类,所以我们猜测不需要使用具有相同数据的两个类,并放弃了租户行类和费用行类。

另一方面;租金行中包含一个公寓和12个租金的数组。在支付一年的第一次租金之前不存在;此后,租金被插入到现有的行中。这比租金和费用更复杂,所以我们将把租金行作为一个类。这就使得租金支付类除了租金金额之外没有任何数据,将取消这个类

发现属性:许多我们拒绝作为类的名词将是类中属性(成员数据)的候选对象。

举个栗子:租户类将具有”租户名称“、”公寓号码“,而费用类将具有”收款人、月、日期、金额和预算类别“

从动词到消息:消息实际上是对对象中的成员函数的调用,所以发现消息与发现接受该消息的类的成员函数是相同的,并不是每个动词都是信息的候选词,有些则与从用户那里获取信息、显示信息或做其他事情有关。

1、作为一个例子,让我们看看显示租户列表的用例:

The program displays the Tenant List, each row of which contains an apartment number
and the tenant’s name.
我们所说的"程序"实际上是指用户界面屏幕,所以"显示"意味着用户界面屏幕发送一条消息--调用租户列表类中的一个成员函数,告诉它显示自己。display()
2、用例添加一个新租户
The program presents the Tenant Input screen, which prompts the user to enter the new
tenant’s name and apartment number. It then places this information on a new row in the
Tenant List. This list is sorted by apartment number.
"presents"动词是指用户界面屏幕向租户输入屏幕发送一条消息,告诉它显示自己并从用户那里获取数据。此消息可能是对租户输入屏幕中的成员函数的调用。getTenant()
"prompts"和”enter“都是指租户输入屏幕与用户的沟通。它们并不表示面向对象意义上的消息。相反,getTenant()会显示提示并记录用户的响应(租户的姓名和公寓号码)
"places”意味着租户输入屏幕向租户列表类发送消息,可能会有一个新的租户对象作为参数。然后,该租户列表对象可以将此新对象插入到其列表中。insertTenant()
“is sorted”的动词不是一条消息,也不是任何形式的交流,而是对租户名单的描述
类图:
UML序列图:两种UML交互图之一
协作图:两者都显示了事件是如何随着时间的推移而展开的,但序列图以一种更图形化的方式描述了时间
在序列图中:纵轴表示时间,从顶部开始,然后向下流动。顶部是包含将参与用例的对象名称的矩形。操作通常从左边的对象向右侧的对象发送消息开始。序列图显示的是对象,而不是类。我们将关系消息序列,消息从一个对象发送到另一个对象,而不是从一个类发送到另一个类。
从每个对象向下延伸的是一条被称为生命线的虚线。这表明该对象存在于特定的时间。如果该对象被删除,则其声明线将在此时停止。

 “启动程序”的顺序图:

当程序第一次启动时,它定义了一个名为用户界面的类来处理用例中讨论的用户界面屏幕。假设程序创建了这个类的一个对象,称为用户接口。正是这个对象启动了所有的用例。它将出现在序列图的左边。

当用户接口对象开始运行时,它的第一个任务是在程序中创建三个主要的数据结构:类的租户列表、租赁记录和扩展记录的对象。事实证明,程序用新对象创建这些对象,所以它们生来就没有名称;只有指向它们的指针才有名称,UML允许用几种方式编写对象名称。如果您不知道实际名称,则可以使用冒号和类名:tenantList。在图表中,下划线和冒号提醒您,该名称适用于对象,而不是类

 对象矩形的垂直位置显示了创建它们的时间,从类帐篷列表的对象开始。所有这些对象将在程序的生命周期继续存在,因此它们的生命线一直延伸到图的底部。时间维度不是尺度;它只显示各种事件的关系。

水平线表示消息。实心箭头表示一个正常的同步函数调用。

用户界面下的矩形称为激活框(或控制焦点)。它表示其对象处于活动状态。在正常的程序中,”活动“是指对象的成员函数正在执行,或者调用了另一个尚未返回的函数。此图中的其他三个对象不是活动状态,因为用户界面尚未向他们发送消息,告诉它们要做什么

”显示租户名单“的顺序图:

让我们来检查另一个序列图。这个例子,显示了租户列表的用例:

函数返回用虚线表示。注意,当一个成员函数被另一个对象调用时,对象才会活动(它们的生命线有一个活动框)。消息行可以显示正在被调用的成员函数的名称。
在这里,用户界面告诉租户列表对象显示自己(通过调用display()函数),而租户列表对象依次告诉它包含的所有租户对象显示自己。”*“表示此消息将被重复发送,而括号中的短语[for all tenant objects]指定了此重复的条件。(在程序中,我们实际上将使用 cout<<,而不是如图所示的display() 功能)。

”新增一个新租户“的顺序图:

这里我们把房东作为一个对象,有它自己的活动箱。这使我们能够显示程序和用户之间的交互。

用户告诉程序添加一个新的租户。用户接口对象创建一个类输入的新对象。此对象从用户中获取租户的数据,创建一个新的租户对象,并调用租户列表类以插入新创建的租户。当他完成时,它将删除意图输入屏幕对象。输入屏幕生命线末端的大”X“显示它已经被删除了

我们所展示的序列图只处理每个用例的主要长江,有一些方法可以在序列图上显示其他场景,也可以为每个场景创建一个新的图。

编写代码

最终、借助用例图、详细的用例、类图、和序列图编写代码。

头文件:

#pragma once
#include<iostream>
#include<vector>
#include<set>
#include<string>
#include<algorithm> //sort
#include<numeric> //accumulate
using namespace std;
void getaLine(string& inStr);   //获取文本行
char getaChar();    
class tenant
{
private:
	string name;    //租户的名字
	int aptNUmber;  //租户的公寓号
public:
	tenant(string n, int aNo);
	~tenant();
	int getAptNumber();
	friend bool operator <(const tenant&, const tenant&);
	friend bool operator == (const tenant&, const tenant&);
	friend ostream& operator <<(ostream&, const tenant&);
};
class compareTenants {
public:
	bool operator()(tenant*, tenant*)const;
};
class tenantList {
private:
	set<tenant*, compareTenants> setPtrsTens;
	set<tenant*, compareTenants>::iterator iter;
public:
	~tenantList();  //析构函数 删除租户
	void insertTenant(tenant*);  //将租户列入名单
	int getAptNo(string); //返回公寓编号
	void display();//显示租户列表
};
class tenantInputScreen
{
private:
	tenantList* ptrTenantList;
	string tName;
	int aptNo;
public:
	tenantInputScreen(tenantList* ptrTL) :ptrTenantList(ptrTL) {}
	void getTenant();
};
class rentRow
{
private:
	int aptNo;
	float rent[12];
public:
	rentRow(int);
	void setRent(int, float);  //记录一个月的租金
	float getSumOfRow();   //返还租金金额
	friend bool operator < (const rentRow&, const rentRow&);
	friend bool operator ==(const rentRow&, const rentRow&);
	friend ostream& operator <<(ostream&, const rentRow&);
};
class compareRows {
public:
	bool operator()(rentRow*, rentRow*)const;
};
class rentRecord
{
private:
	//指向rentRow对象的指针集(每个租户一个)
	set<rentRow*, compareRows> setPtrsRR;
	set<rentRow*, compareRows>::iterator iter;
public:
	~rentRecord();
	void insertRent(int, int, float);
	void display();
	float getSumOfRents();  //合计所有租金
};
class rentInputScreen
{
private:
	tenantList* ptrTenantList;
	rentRecord* ptrRentRecord;
	string renterName;
	float rentPaid;
	int month;
	int aptNo;
public:
	rentInputScreen(tenantList* ptrTL, rentRecord* ptrRR) :ptrTenantList(ptrTL), ptrRentRecord(ptrRR) {}
	void getRent();
};
class expense
{
public:
	int month, day;
	string categroy, payee;
	float amount;
	expense() {}
	expense(int m, int d, string c, string p, float a) :month(m), day(d), categroy(c), payee(p), amount(a) {}
	friend bool operator < (const expense&, const expense&);
	friend bool operator ==(const expense&, const expense&);
	friend ostream& operator <<(ostream&, const expense&);
};
class compareDates { //功能函数--比较功能
public:
	bool operator()(expense*, expense*)const;
};
class compareCategories { //功能函数--比较功能
public:
	bool operator()(expense*, expense*)const;
};
class expenseRecord {
private:
	//指向费用的指针的vector
	vector<expense*>vectPtrsExpenses;
	vector<expense*>::iterator iter;
};
class expenseInputScreen
{
private:
	expenseRecord* ptrExpenseRecord;
public:
	expenseInputScreen(expenseRecord*);
	void getExpense();
};
class annualReport
{
private:
	rentRecord* ptrRR;
	expenseRecord* ptrER;
	float expenses, rents;
public:
	annualReport(rentRecord*, expenseRecord*);
	void display();
};
class userInterface
{
private:
	tenantList* ptrTenantList;
	tenantInputScreen* ptrTenantInputScreen;
	rentRecord* ptrRentRecord;
	rentInputScreen* ptrRentInputScreen;
	expenseRecord* ptrExpenseRecord;
	expenseInputScreen* ptrExpenseInputScreen;
	annualReport* ptrAnnualReport;
	char ch;
public:
	userInterface();
	~userInterface();
	void interact();
};

 在所有聚合中 ,我们选择存储指针,而不是实际对象,以避免每次存储实际对象时发生复制

#include "landlord.h"
int main()
{
	userInterface theUserInterface;
	theUserInterface.interact();
	return 0;
}
void getaLine(string& inStr) //获取文本行
{
	char temp[21];
	cin.get(temp, 20, '\n');
	cin.ignore(20, '\n');
	inStr = temp;
}
//--------------------------------------------------------------
char getaChar() 
{
	char ch = cin.get();
	cin.ignore(80, '\n');
	return ch;
}
//--------------------------------------------------------------
tenant::tenant(string n, int aNo) : name(n), aptNumber(aNo){}
//--------------------------------------------------------------
tenant::~tenant(){}
//--------------------------------------------------------------
int tenant::getAptNumber()
{
	return aptNumber;
}
//--------------------------------------------------------------
bool operator < (const tenant& t1, const tenant& t2)
{
	return t1.name < t2.name;
}
//--------------------------------------------------------------
bool operator == (const tenant& t1, const tenant& t2)
{
	return t1.name == t2.name;
}
//--------------------------------------------------------------
ostream& operator << (ostream& s, const tenant& t)
{
	s << t.aptNumber << '\t' << t.name << endl; return s;
}
//-------------------------------------------------------------- 
method for class tenantInputScreen//
void tenantInputScreen::getTenant() //get tenant info
{
	cout << "Enter tenant’s name(George Smith) :";
	getaLine(tName);
	cout << "Enter tenant’s apartment number(101) :";
	cin >> aptNo;
	cin.ignore(80, '\n'); //make tenant
	tenant* ptrTenant = new tenant(tName, aptNo);
	ptrTenantList->insertTenant(ptrTenant); //send to tenant list
}

bool compareTenants::operator () (tenant* ptrT1,
	tenant* ptrT2) const
{
	return *ptrT1 < *ptrT2;
}
//--------------------------------------------------------------
///methods for class tenantList/
tenantList::~tenantList() //destructor
{
	while (!setPtrsTens.empty()) //delete all tenants,
	{ //remove ptrs from set
		iter = setPtrsTens.begin();
		delete* iter;
		setPtrsTens.erase(iter);
	}
} // end ~tenantList()
//--------------------------------------------------------------
void tenantList::insertTenant(tenant* ptrT)
{
	setPtrsTens.insert(ptrT); //insert
}
//-------------------------------------------------------------- 
int tenantList::getAptNo(string tName) //name on list?
{
	int aptNo;
	tenant dummy(tName, 0);
	iter = setPtrsTens.begin();
	while (iter != setPtrsTens.end())
	{
		aptNo = (*iter)->getAptNumber(); //look for tenant
		if (dummy == **iter++) //on the list?
			return aptNo; //yes
	}
	return -1; //no
}
//-------------------------------------------------------------- 
void tenantList::display() //display tenant list
{
	cout << "\nApt#\tTenant name\n------------------ - \n";
	if (setPtrsTens.empty())
		cout << "* **No tenants * **\n";
	else
	{
		iter = setPtrsTens.begin();
		while (iter != setPtrsTens.end())
			cout << **iter++;
	}
} // end display()
//--------------------------------------------------------------
/methods for class rentRow//
rentRow::rentRow(int an) : aptNo(an) // 1-arg constructor
{
	fill(&rent[0], &rent[12], 0);
}
//--------------------------------------------------------------
void rentRow::setRent(int m, float am)
{
	rent[m] = am;
}
//-------------------------------------------------------------- 
float rentRow::getSumOfRow() // sum of rents in row
{
	return accumulate(&rent[0], &rent[12], 0);
}
//--------------------------------------------------------------
bool operator < (const rentRow& t1, const rentRow& t2)
{
	return t1.aptNo < t2.aptNo;
}
//--------------------------------------------------------------
bool operator == (const rentRow& t1, const rentRow& t2)
{
	return t1.aptNo == t2.aptNo;
}
//--------------------------------------------------------------
ostream& operator << (ostream& s, const rentRow& an)
{
	s << an.aptNo << '\t'; //print apartment number
	for (int j = 0; j < 12; j++) //print 12 rents
	{
		if (an.rent[j] == 0)
			s << "0";
		else
			s << an.rent[j] << " ";
	}
	s << endl;
	return s;
}

bool compareRows::operator () (rentRow* ptrR1,
	rentRow* ptrR2) const
{
	return *ptrR1 < *ptrR2;
}
///methods for class rentRecord/
rentRecord::~rentRecord() //destructor
{
	while (!setPtrsRR.empty()) //delete rent rows,
	{ //remove ptrs from set
		iter = setPtrsRR.begin();
		delete* iter;
		setPtrsRR.erase(iter);
	}
}
//--------------------------------------------------------------
void rentRecord::insertRent(int aptNo, int month, float amount)
{
	rentRow searchRow(aptNo); //temp row with same aptNo 
	iter = setPtrsRR.begin(); //search setPtrsRR
	while (iter != setPtrsRR.end())
	{
		if (searchRow == **iter) //rentRow found?
		{ //yes,
			(*iter)->setRent(month, amount); //put rent in row
			return;
		}
		else
			iter++;
	} //didn’t find it
	rentRow* ptrRow = new rentRow(aptNo); //make new row
	ptrRow->setRent(month, amount); //put rent in row
	setPtrsRR.insert(ptrRow); //put row in vector
} // end insertRent() 
//--------------------------------------------------------------
void rentRecord::display()
{
	cout << "\nAptNo\tJan Feb Mar Apr May Jun"
		<< "Jul Aug Sep Oct Nov Dec\n"
		<< "-------------------------------- -"
		<< "-------------------------------- - \n";
	if (setPtrsRR.empty())
		cout << "* **No rents * **\n";
	else
	{
		iter = setPtrsRR.begin();
		while (iter != setPtrsRR.end())
			cout << **iter++;
	}
}
//--------------------------------------------------------------
float rentRecord::getSumOfRents() // return sum of all rents
{
	float sumRents = 0.0;
	iter = setPtrsRR.begin();
	while (iter != setPtrsRR.end())
	{
		sumRents += (*iter)->getSumOfRow();
		iter++;
	}
	return sumRents;
}
//--------------------------------------------------------------
/methods for class rentInputScreen//
void rentInputScreen::getRent()
{
cout << "Enter tenant’s name : ";
getaLine(renterName);
aptNo = ptrTenantList->getAptNo(renterName);
if (aptNo > 0) // if name found,
{ // get rent amount
	cout << "Enter amount paid(345.67) :";
	cin >> rentPaid;
	cin.ignore(80, '\n');
	cout << "Enter month rent is for (1 - 12) : ";
	cin >> month;
	cin.ignore(80, '\n');
	month--; // (internal is 0-11)
	ptrRentRecord->insertRent(aptNo, month, rentPaid);
}
else // return
cout << "No tenant with that name.\n";
} // end getRent()
//--------------------------------------------------------------
///methods for class expense
bool operator < (const expense& e1, const expense& e2)
{ // compares dates
	if (e1.month == e2.month) // if same month,
		return e1.day < e2.day; // compare days
	else // otherwise,
		return e1.month < e2.month; // compare months
}
//--------------------------------------------------------------
bool operator == (const expense& e1, const expense& e2)
{
	return e1.month == e2.month && e1.day == e2.day;
}
//--------------------------------------------------------------
ostream& operator << (ostream& s, const expense& exp)
{
	s << exp.month << '/' << exp.day << '\t' << exp.payee << '\t';
	s << exp.amount << '\t' << exp.categroy << endl;
	return s;
}
//--------------------------------------------------------------

bool compareDates::operator () (expense* ptrE1,
	expense* ptrE2) const
{
	return *ptrE1 < *ptrE2;
}
//--------------------------------------------------------------
bool compareCategories::operator () (expense* ptrE1,
	expense* ptrE2) const
{
	return ptrE1->categroy < ptrE2->categroy;
}
//--------------------------------------------------------------
//methods for class expenseRecord///
expenseRecord::~expenseRecord() //destructor
{
	while (!vectPtrsExpenses.empty()) //delete expense objects,
	{ //remove ptrs from vector
		iter = vectPtrsExpenses.begin();
		delete* iter;
		vectPtrsExpenses.erase(iter);
	}
}
//--------------------------------------------------------------
void expenseRecord::insertExp(expense* ptrExp)
{
	vectPtrsExpenses.push_back(ptrExp);
}
//--------------------------------------------------------------
void expenseRecord::display()
{
	cout << "\nDate\tPayee\t\tAmount\tCategory\n"
		<< "----------------------------------------\n";
	if (vectPtrsExpenses.size() == 0)
		cout << "* **No expenses * **\n";
	else
	{
		sort(vectPtrsExpenses.begin(), vectPtrsExpenses.end(), compareDates());
		iter = vectPtrsExpenses.begin();
		while (iter != vectPtrsExpenses.end())
			cout << **iter++;
	}
}
//-----------------------------------------------------------
float expenseRecord::displaySummary() // used by annualReport
{
	float totalExpenses = 0; //total, all categories
	if (vectPtrsExpenses.size() == 0)
	{
		cout << "\tAll categories\t0\n";
		return 0;
	}
	// sort by category
	sort(vectPtrsExpenses.begin(),
		vectPtrsExpenses.end(), compareCategories());
	// for each category, sum the entries
	iter = vectPtrsExpenses.begin();
	string tempCat = (*iter)->categroy;
	float sumCat = 0.0;
	while (iter != vectPtrsExpenses.end())
	{
		if (tempCat == (*iter)->categroy)
			sumCat += (*iter)->amount; // same category
		else
		{ // different category
			cout << '\t' << tempCat << '\t' << sumCat << endl;
			totalExpenses += sumCat; // add previous category
			tempCat = (*iter)->categroy;
			sumCat = (*iter)->amount; // add final amount
		}
		iter++;
	} // end while
	totalExpenses += sumCat; // add final category
	cout << '\t' << tempCat << '\t' << sumCat << endl;
	return totalExpenses;
} // end displaySummary()
//-----------------------------------------------------------
expenseInputScreen::expenseInputScreen(expenseRecord* per) :
	ptrExpenseRecord(per){}
//-----------------------------------------------------------
void expenseInputScreen::getExpense()
{
	int month, day;
	string category, payee;
	float amount;
	cout << "Enter month(1 - 12) : ";
	cin >> month;
	cin.ignore(80, '\n');
	cout << "Enter day(1 - 31) : ";
	cin >> day;
	cin.ignore(80, '\n');
	cout << "Enter expense category(Repairing, Utilities) : ";
	getaLine(category);
	cout << "Enter payee"
		<< "(Bob’s Hardware, Big Electric Co) : ";
	getaLine(payee);
	cout << "Enter amount(39.95) : ";
	cin >> amount;
	cin.ignore(80, '\n');
	expense* ptrExpense = new expense(month, day, category, payee, amount);
	ptrExpenseRecord->insertExp(ptrExpense);
}
//-----------------------------------------------------------
//methods for class annualReport/
annualReport::annualReport(rentRecord* pRR,
	expenseRecord* pER) :
	ptrRR(pRR), ptrER(pER)
{ /* empty*/
}
//-----------------------------------------------------------
void annualReport::display()
{
	cout << "Annual Summary\n--------------\n";
	cout << "Income\n";
	cout << "\tRent\t\t";
	rents = ptrRR->getSumOfRents();
	cout << rents << endl;
	cout << "Expenses\n";
	expenses = ptrER->displaySummary();
	cout << "\nBalance\t\t\t" << rents - expenses << endl;
}
//-----------------------------------------------------------
methods for class userInterface//
userInterface::userInterface()
{
	//these reports exist for the life of the program
	ptrTenantList = new tenantList;
	ptrRentRecord = new rentRecord;
	ptrExpenseRecord = new expenseRecord;
}
//-----------------------------------------------------------
userInterface::~userInterface()
{
	delete ptrTenantList;
	delete ptrRentRecord;
	delete ptrExpenseRecord;
}
//-----------------------------------------------------------
void userInterface::interact()
{
	while (true)
	{
		cout << "Enter 'i' to input data, \n"
			<< "'d' to display a report, \n"
			<< "'q' to quit program :";
		ch = getaChar();
		if (ch == 'i') // enter data
		{
			cout << "Enter 't' to display tenants, \n"
				<< "'r' to display rents\n"
				<< "'e' to display expenses:\n";
			ch = getaChar();
			switch (ch)
			{
				//input screens exist only while being used
			case 't':
				ptrTenantInputScreen = new tenantInputScreen(ptrTenantList);
				ptrTenantInputScreen->getTenant();
				delete ptrTenantInputScreen;
				break;
			case 'r': 
				ptrRentInputScreen = new rentInputScreen(ptrTenantList, ptrRentRecord);
				ptrRentInputScreen->getRent();
				delete ptrRentInputScreen;
				break;
			case 'e': 
				ptrExpenseInputScreen = new expenseInputScreen(ptrExpenseRecord);
				ptrExpenseInputScreen->getExpense();
				delete ptrExpenseInputScreen;
				break;
			default: cout << "Unknown input option\n";
				break;
			} // end switch 
		} // end if
		else if (ch == 'd') // display data
		{
			cout << "Enter 't' to display tenants, \n"
				<<"'r' to display rents\n"
				<< "'e' to display expenses, \n"
				<< "'a' to display annual report : ";
			ch = getaChar();
			switch (ch)
			{
			case 't': ptrTenantList->display();
				break;
			case 'r': ptrRentRecord->display();
				break;
			case 'e': ptrExpenseRecord->display();
				break;
			case 'a':
				ptrAnnualReport = new annualReport(ptrRentRecord,ptrExpenseRecord);
				ptrAnnualReport->display();
				delete ptrAnnualReport;
				break;
			default: cout <<"Unknown display option\n";
				break;
			} // end switch
		} // end elseif
		else if (ch == 'q')
			return; // quit
		else
			cout << "Unknown option.Enter only ‘i’, ‘d’ or ‘q’\n";
	} 
} 

最终的想法

在任何规模的真是项目中,开发过程可能不会像我们在本章中所描述的那样顺利。我们所展的每个阶段都需要进行多次迭代。程序员可能会发现自己对用户的意图感到困惑,需要在构建阶段中返回到精化阶段。用户可能会在过程的后期改变他们想要的想法,需要返回到早期阶段。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值