问答题[问题1] 试画出ER图,并在图上注明属性、联系类型、实体标识符;
问答题【说明】设某城市有n个车站,并有m条公交线路连接这些车站,设这些公交车都是单向的,这n个车站被顺序编号为0至n-1。本程序,输入该城市的公交线路数、车站个数,以及各公交线路上的各站编号,求得从站0出发乘公交车至站n-1的最少换车次数。 程序利用输入信息构建一张有向图G(用邻接矩阵g表示),有向图的顶点是车站,若有某条公交线路经i站到达j站,就在顶点i到顶点j之间设置一条权为1的有向边<i,j>。如果这样,从站点x至站点y的最少上车次数便对应图G中从点x到点y的最短路径长度。而程序要求的换车次数就是上车次数减1。 #include <stdio.h> #define M 20 #define N 50 int a[N+1]; /*用于存放一条线路上的各站编号*/ int g[N][N]; /*严存储对应的邻接矩阵*/ int dist[N]; /*严存储站0到各站的最短路径*/ int m, n; void buildG() int i, j, k, sc, dd printf(“输入公交线路数,公交站数/n”); scanf("%d%d",&m,&n); for (i=0;i<n;i++) /*邻接矩阵清0*/ for(j=0;j<n;j++) g[i][j]=0; for(i=0;i<m;i++) printf("沿第%d条公交线路的各站编号(0<=编号<=%d,-1结束):/n)",i+1,n-1); sc=0; /* 当前线路站计数器*/ while(1) scanf("%d",&dd); if(dd=-1)break; if(dd>=0 && dd<n) (1) ; a[sc]=-1; for(k=1;a[k]>=0;k++) /*处理第i+1条公交线路*/ for(j=0;j<k;j++) g (2) =1; int minLen() int j,k; for(j=0;j<n;j++) dist[j]=g[0][j]; dist[0]=1; do for(k=-1,j=0;j<n;j++) /*找下一个最少上车次数的站*/ if(dist[j]>0 &&(k==-1||dist[j]<dist[k])) k=j; if(k<0||k==n-1) break; dist[k]=-dist[k]; /*设置k站已求得上车次数的标记*/ for (j=1;j<n;j++) /*调整经过k站能到达的其余各站的上车次数*/ if( (3) && (dist[j]=0||-dist[k]+1<dist[j])) dist[j]= (4) ; while(1); j=dist[n-1]; return (5) ;void main() int t; buildG(); if((t=minLen())<0) printf("无解!/n");else printf(“从0号站到%d站需换车%d次/n”,n-1,t);
问答题[说明]
某餐厅供应各种标准的营养套餐。假设菜单上共有n项食物m
1
,m
2
,…,m
n
每项食物m
i
的营养价值为v
i
,价格为p
i
,其中i=1,2,…,n,套餐中每项食物至多出现一次。客人常需要一个算法来求解总价格不超过M的营养价值最大的套餐。
问答题【说明】 算法2-1是用来检查文本文件中的圆括号是否匹配。若文件中存在圆括号没有对应的左括号或者右括号,则给出相应的提示信息,如下所示: 文件 提示信息 (1+2) abc) 缺少对应左括号:第2行,第4列 ((def)gx) 缺少对应左括号:第3行,第10列 (((h) ij)(k (1ml) 缺少对应右括号:第5行,第4列;第4行,第1列 在算法2-1中,stack为一整数栈。算法中各函数的说明见表4。 表4 函数名 函数功能 push (int i) 将整数i压人栈stack中 pop( ) stack的栈顶元素出栈 empty( ) 判断stack栈是否为空。若为空,函数返回1,否则函数返回0 nextch( ) 读取文本文件中的下—个字符,井返回该字符的ASCII值,将字 符所在的行号以及字符在行中的位置分别存储到变量row和col 中,若遇到文件结束符,则将变量EOF置为true kind (char ch) 判断字符ch是左括号还是右括号,若是左括号,函数返回1, 若是右括号,函数返回2,若两者都不是,函数返回。 【算法2-1】将栈stack 置空,置EOF为falsech < - nextch();while( not EOF) k < - kind(CH); if(k== (1) ) push( (2) );push( (3) ); elseif(k== (4) ) if(not empty()) pop( ) ;pop( ); else 显示错误信息(缺少对应左括号或右括号); 显示行号row;显示列号col; endif endif ch < - nextch( ); endwhileif(not empty()) 显示错误信息(缺少对应左括号或右括号); while(not empty()) row < - pop() ; col <- pop(); 显示行号row; 显示列号col; endwhile endif 为了识别更多种类的括号,对算法2-1加以改进后得到算法2-2。算法2-2能够识别圆括号、方括号和花括号(不同类型的括号不能互相匹配)。改进后,函数kind(char ch)的参数及其对应的返回值见表5。 表五 ch ( ) [ ] 其他 返回值 1 2 3 4 5 6 0 【算法2-2】 将栈stack置空,置EOF为false ch< -nextch(); while(not EOF) k <-kind(ch); if( k >0) if( 判断条件1 ) push( (5) );push( (6) );push( (7) ); elseif( 判断条件2 and 判断条件3 ) pop() ;pop() ;pop(); else 显示行号row; 显示列号col; endif endif ch < - nextch();endwhileif(not empty( ) ) 显示错误信息(缺少对应左括号或右括号); while( not empty( ) ) pop( ); row←pop( ); col←pop( ); 显示行号row;显示列号col; endwhileendif
问答题[说明]某大学城图书馆需要在无线阅览厅的某些位置上放置无线接入点AP(AccessPoin)。假设每个无线AP覆盖范围的半径是6米,因此必须使得每台笔记本电脑上的无线网卡到某个无线AP的直线距离不超过6米。为了简化问题,假设所有无线网卡在同一直线上,并且无线AP沿该直线放置。该问题可以建模为如图1-13所示,其中直线表示无线网卡所在的直线,实心正方形表示无线网卡。现采用贪心策略实现用尽可能少的无线AP覆盖所有的无线网卡。实现贪心算法的流程如图1-14所示。其中,①d[i](1≤i≤N)表示第i张无线网卡到通道A端的距离,N表示无线网卡的总数,无线网卡的编号按照无线网卡到通道A端的距离从小到大进行编号:②s[k]表示第k(k≥1)个无线AP到通道A端的距离。算法结束后k的值为无线AP的总数。
问答题
问答题问题:1.4 (5分)
实际的证券交易通常是在证券交易中心完成的,因此,该平台的“证券交易”功能需将交易信息传递给证券交易中心。针对这个功能需求,需要对图1-1和图1-2进行哪些修改,请用200字以内的文字加以说明。
问答题阅读以下算法说明和流程图,回答问题1和问题2。【算法说明】下面是一段插入排序的程序,将R[k+1]插入到R[1...k]的适当位置。R[0]=R[k+1];j=k;while(R[j]>R[0]){R[j+1]=R[j];j--;}R[j+1]=R[0];【流程图】【测试用例设计】(while循环次数为0、1、2次){{B}}表3测试用例表{{/B}}
问答题阅读下列说明和算法,回答问题1和问题2。
【说明】
算法2-1是用来检查文本文件中的圆括号是否匹配。若文件中存在圆括号没有对应的左括号或者右括号,则给出相应的提示信息,如下所示:
文件
提示信息 (1+2) abc)
缺少对应左括号:第2行,第4列 ((def)gx)
缺少对应左括号:第3行,第10列 (((h)
ij)(k (1ml)
缺少对应右括号:第5行,第4列;第4行,第1列
在算法2-1中,stack为一整数栈。算法中各函数的说明见表4。
{{B}}表4{{/B}}
函数名
函数功能
push (int i)
将整数i压人栈stack中
pop( )
stack的栈顶元素出栈
empty( )
判断stack栈是否为空。若为空,函数返回1,否则函数返回0
nextch( )
读取文本文件中的下—个字符,井返回该字符的ASCII值,将字符所在的行号以及字符在行中的位置分别存储到变量row和col中,若遇到文件结束符,则将变量EOF置为true
kind (char ch)
判断字符ch是左括号还是右括号,若是左括号,函数返回1,若是右括号,函数返回2,若两者都不是,函数返回。【算法2-1】将栈stack
置空,置EOF为false ch < - nextch(); while( not EOF) k < - kind(CH); if(k=={{U}} (1)
{{/U}}) push({{U}} (2) {{/U}});push({{U}} (3) {{/U}}); elseif(k=={{U}} (4) {{/U}}) if(not
empty()) pop( ) ;pop( ); else 显示错误信息(缺少对应左括号或右括号); 显示行号row;显示列号col; endif endif
ch < - nextch( ); endwhile if(not empty()) 显示错误信息(缺少对应左括号或右括号); while(not
empty()) row < - pop() ; col <- pop(); 显示行号row; 显示列号col; endwhile endif
为了识别更多种类的括号,对算法2-1加以改进后得到算法2-2。算法2-2能够识别圆括号、方括号和花括号(不同类型的括号不能互相匹配)。改进后,函数kind(char
ch)的参数及其对应的返回值见表5。 {{B}}表五{{/B}}
ch
(
)
{
}
[
]
其他
返回值
1
2
3
4
5
6
0
【算法2-2】 将栈stack置空,置EOF为false ch<
-nextch(); while(not EOF)
k <-kind(ch); if( k >0)
if({{U}} 判断条件1 {{/U}})
push({{U}} (5) {{/U}});push({{U}}
(6) {{/U}});push({{U}} (7) {{/U}});
elseif({{U}} 判断条件2 {{/U}}and{{U}} 判断条件3
{{/U}})
pop() ;pop() ;pop();
else
显示行号row; 显示列号col;
endif endif ch < -
nextch();endwhileif(not empty( ) )
显示错误信息(缺少对应左括号或右括号); while( not empty( )
)
pop( ); row←pop( ); col←pop( );
显示行号row;显示列号col; endwhileendif
问答题阅读下列说明,根据要求回答下列问题。[说明]某地区举行篮球比赛,需要开发一个比赛信息管理系统来记录比赛的相关信息。[需求分析结果]1.登记参赛球队的信息。记录球队的名称、代表地区、成立时间等信息。系统记录球队的每个队员的姓名、年龄、身高、体重等信息。每个球队有一个教练负责管理球队,一个教练仅负责一个球队。系统记录教练的姓名、年龄等信息。2.安排球队的训练信息。比赛组织者为球队提供了若干个场地,供球队进行适应性训练。系统记录现有的场地信息,包括场地名称、场地规模、位置等信息。系统可为每个球队安排不同的训练场地,如表8-6所示。系统记录训练场地安排的信息。表8-6训练安排表球队名称场地名称训练时间解放军一号球场2008-06-0914:00~18:00解放军一号球场2008-06-1209:00~12:00解放军二号球场2008-06-1114:00~18:00山西一号球场2008-06-1009:00~12:003.安排比赛。该赛事聘请了专职裁判,每场比赛只安排一个裁判。系统记录裁判的姓名、年龄、级别等信息。系统按照一定的规则,首先分组,然后根据球队、场地和裁判情况,安排比赛(每场比赛的对阵双方分别称为甲队和乙队)。记录参赛球队、比赛时间、比分、场地名称等信息,如表8-7所示。表8-7 比赛安排表 A组:甲队——乙队场地名称比赛时间裁判比分解放军—北京一号球场2008-06-1715:00李大明天津—山西一号球场2008-06-1719:00胡学梅 B组:甲队——乙队场地名称比赛时间裁判比分上海—安徽二号球场2008-06-1715:00丁鸿平山东—辽宁二号球场2008-06-1719:00郭爱琪4.所有球员、教练和裁判可能出现重名情况。[概念模型设计]根据需求阶段收集的信息,设计的实体联系图和关系模式(不完整)如下。1.实体联系图(如图8-17所示)2.关系模式●教练(教练编号,姓名,年龄)●队员(队员编号,姓名,年龄,身高,体重,(a))●球队(球队名称,代表地区,成立时间,(b))●场地(场地名称,场地规模,位置)●训练记录((c))●裁判(裁判编号,姓名,年龄,级别)●比赛记录((d))
问答题[说明][算法4-1]的功能是:用来检查文本文件中的圆括号是否匹配。若文件中存在圆括号没有对应的左括号或者右括号,则给出相应的提示信息,如图4-18所示。在[算法4-1]中,stack为一整数栈。算法中各函数的说明如表4-16所示。{{B}}表4-16各函数的功能说明表{{/B}}{{B}}函数名{{/B}}{{B}}函数功能{{/B}}push(inti)将整数i压入栈stack中pop()stack的栈顶元素出栈empty()判断stack栈是否为空.若为空,函数返回1,否则函数返回0nextch()读取文本文件中的下一个字符,并返回该字符的ASCII值,将字符所在的行号以及字符在行中的位置分别存储到变量row和col中,若遇到文件结束符,则将变量EOF置为truekind(charch)判断字符ch是左括号还是右括号,若是左括号,函数返回1;若是右括号,函数返回2;若两者都不是,函数返回0[算法4-1]将栈stack置空,置EOF为false为了识别更多种类的括号,对[算法4-1]加以改进后得到[算法4-2]。[算法4-2]能够识别圆括号、方括号和花括号(不同类型的括号不能互相匹配)。改进后,函数kind(charch)的参数及其对应的返回值如表4-17所示。{{B}}表4-17函数Kind(charch)的参数及其对应的返回值{{/B}}ch(){}[]其他返回值1234560[算法4-2][问题1]请将[算法4-1]和[算法4-2]中,(1)~(7)空缺处的内容补充完整。[问题2]请从以下选项中选择相应的判断逻辑填补[算法4-2]中的“判断条件1”至“判断条件3”。注意,若“判断条件2”的逻辑判断结果为假,就无需对“判断条件3”进行判断。判断条件1:{{U}}(8){{/U}}判断条件2:{{U}}(9){{/U}}判断条件3:{{U}}(10){{/U}}[供选择的答案]A.栈顶元素表示的是与当前字符匹配的左括号B.栈顶元素表示的是与当前字符匹配的右括号C.字符是左括号D.字符是右括号E.栈不空F.栈空G.字符是括号
问答题[说明]现欲构造一文件/目录树,采用组合(Composite)设计模式来设计,得到的类图如下图所示。[Java程序]importJava.util.ArrayList;importJava.util.List;______classAbstractFile{protectedStringname;publicvoidprintName(){System.out.println(name);}publicabstractbooleanaddChiid(AbstractFilefile);publicabstractbooleanremoveChild(AbstractFilefile);publicabstractList<AbstractFile>getChildren();}classFileextendsAbstractFile{publicFile(Stringname){this.name=name;}publicbooleanaddChild(AbstractFilefile){returnfalse;}publicbooleanremoveChild(AbstractFilefile){returnfalse;}publicList<AbstractFile>getChildren(){return______;}}classFolderextendsAbstractFile{privateList<AbstractFile>childList;publicFolder(Stringname){this.name=name;this.childList=newArrayList<AbstractFile>();}publicbooleanaddChild(AbstractFilefile){returnchildList.add(file);}publicbooleanremoveChild(AbstractFilefile){returnchildList.remove(file);}public______<AbstractFile>getChildren(){return______;}}publicclassClient{publicstaticvoidmain(String[]args){//构造一个树型的文件/目录结构AbstractFilerootFolder=newFolder("c:\");AbstractFilecompositeFolder=newFolder("composite");AbstractFilewindowsFolder=newFolder("windows");AbstractFilefile=newFile("TestComposire.java");rootFolder.addChiid(compositeFolder);rootFolder.addChiid(windowsFoider);compositeFolder.addChild(file);//打印目录文件树printTree(rootFolder);}privatestaticvoidprintTree(AbslractFileifile){ifile.printName();List<AbsiractFile>children=ifile.getChildren;if(chiidren==null)return;for(AbstractFileifile.children){______;}}}该程序运行后输出结果为:c:compositeTestComposite.javaWindows
问答题假定SP表存储供应情况,如下的SQL语句是用于查询“产地为‘Beijing’、零件号为‘P101’的零件的所供应的总数(包括所有供应商)”的不完整语句,请在空缺处填入正确的内容。 SELECT SUM(Qty) FROM SP WHERE PNo=”P101’ (1) PNo (2) (SELECT PNo FROM (3) WHERE city="Beijing") (4) PNo;
问答题【函数3说明】
函数DeleteNode(Bitree * r,int e)的功能是:在树根结点指针为r的二叉查找(排序)树上删除键值为e的结点,若删除成功,则函数返回0,否则函数返回-1。二叉查找树结点的类型定义为:
typedef struct Tnode{
int data; /*结点的键值*/
struct Tnode * Lchild,*Rchild; /*指向左、右子树的指针*/
} * Bitree;
在二叉查找树上删除一个结点时,要考虑三种情况:
①若待删除的结点p是叶子结点,则直接删除该结点;
②若待删除的结点p只有一个子结点,则将这个子结点与待删除结点的父结点直接连接,然后删除结点P;
③若待删除的结点p有两个子结点,则在其左子树上,用中序遍历寻找关键值最大的结点s,用结点s的值代替结点p的值,然后删除结点s,结点s必属于上述①、②情况之一。
【函数3】
int DeleteNode(Bitree * r,int e){
Bitree p=*r,pp,s,c;
while({{U}} (1) {{/U}}){ /*从树根结点出发查找键值为e的结点*/
pp=p;
if(e<p->data)p=p->Lchild;
else p=p->Rchild;
{
if(!p)return-1; /*查找失败*/
if(p->Lchild &&p->Rchild){/*处理情况③*/
s= {{U}}(2) {{/U}}; pp=p;
while({{U}} (3) {{/U}}){pp=s;s=s->Rchild;}
p->data=s->data;p=s;
}
/*处理情况①、②*/
if({{U}} (4) {{/U}})c=p->Lchild;
else c=p->Rchild;
if(p==*r)*r=c;
else if({{U}} (5) {{/U}})pp->Lchild=c;
else pp->Rchild=c;
free(p);
return 0;
}
问答题[程序6]
#include<ioStream.h>
template<class T>class Array;
template<class T>class ArrayBody{
friend{{U}} (1) {{/U}};
T* tpBody;
int iRows,iCurrentRow;
ArrayBOdy(int iRsz,int iCsz){
tpBody={{U}} (2) {{/U}};
iRows=iRsz,iColumns=iCsz;iCurrentRow=-1;
}
public:
T& operator[](int j) {
bool row_error,column_error;
row_error=column_error=false;
try{
if(iCurrentRow<0||iCurrentRow≥iRows)
row_error=;
if(j<0|| j≥iColumns
column_error=;
if(row_error==true || column_error==true)
{{U}} (3) {{/U}};
}
eatch(char) {
if(row error==true)
cerr<<“行下标越界[“<<iCurrentRow<<”]”;
if(column error==true)
cerr<<“列下标越界[“<<j<<”]”;
cout<<“/n”;
}
return tpBody[iCurrentRow * iColumns+j];
}
~ArrayBody(){delere[]tpBody;}
};
template<class T>class Array {
ArrayBody<T> tBody;
public:
ArrayBody<T> & operator[](int i){
{{U}}(4) {{/U}};
return tBody;
};
void main()
{
Array<int> a1(10,20);
Array<double> a2(3,5);
int b1;
double b2;
b1=a1[-5][10]; / * 有越界提示:行下标越界[-5] * /
b1=a1[10][15]; / * 有越界提示:行下标越界[10] * /
b1=a1[1][4]; / * 没有越界提示 * /
b2=a2[2][6]; / * 有越界提示:列下标越界[6] * /
b2=a2[10][20]; / * 有越界提示:行下标越界[10]列下标越界[20] * /
b2=a2[1][4]; / * 没有越界提示 * /
}
问答题【说明】
①在类体中添加函数move(double ax,double ay)的定义,使得点的坐标x和y分别移动 ax和ay个单位。
②在类定义外完成重载的两个构造函数CPosition()和CPosition(double dx,double dy),其中前者为不带参数的构造函数,使CPosition对象的默认值为x=0,y=0,后者为带参数的构造函数,把数据成员x和y分别初始化为参数dx和dy的值。
③完成函数double distance(double bx,double by)的定义,该函数返回*this和点(bx, by)的距离。
注意:除在指定的位置添加语句外,请不要改动程序中的其他语句。
源程序文件test5.cpp清单如下:
#include<iostream.h>
#include<math.h>
class CPosition
{
public:
CPosition();
CPosition(double dx,double dy);
double getx();
double gety();
{{U}} (1) {{/U}}
double distance(double bx,double by);
private:
double x;
double y;
};
{{U}} (2) {{/U}}
{
x=0;y=0;
}
CPosition::CPosition(doub,e dx,doub,e dy)
{
x=dx; y=dy;
}
double CPosition::getx()
{
return x;
}
double CPosition::gety()
{
return y;
}
double CPosition::distance(double bx,double by)
{
{{U}} (3) {{/U}}
}
vold main()
{
double a,b;
cout<<"|nput x,y position of a point:";
cin >> a >> b;
CPosition psA(a,b);
cout<<"Input x,y position of another point:";
cin >>a >> b;
cout <<"The distance is" <<psA.distance(a,b) <<end1;
}
问答题【说明】某供销系统接受顾客的订货单。当库存中某配件的数量小于订购量或库存量低于一定数量时,向供应商发出采货单;当某配件的库存量大于或等于订购量时,或者收到供应商的送货单并更新了库存后,向顾客发㈩提货单。该系统还可随时向总经理提供销售和库存情况表。该供销系统的分层数据流图中部分数据流和文件的组成如下:【文件】配件库存=配件名+规格+数量+允许的最低率库存量【数据流】订货单=配件号+配件名+规格+数量+顾客名+地址提供单=订货单+金额采货单=配件号+配件名+规格+数量+供应商名十地址送货单=配件号+配件名+规格+数量+金额假定顶层图是正确的,“供应商”文件已由其他系统生成。【数据流图】假定题中提供的顶层图是正确的,请回答下列问题:1.【问题1】指出哪张图中缺少了哪些文件。
问答题阅读下列说明和图,回答问题1至问题4,将解答填入对应栏内。【说明】某汽车停车场欲建立一个信息系统,已经调查到的需求如下:1.在停车场的入口和出口分别安装一个自动栏杆、一台停车卡打印机、一台读卡器和一个车辆通过传感器,示意图如下:2.当汽车到达入口时,驾驶员按下停车卡打印机的按钮获取停车卡。当驾驶员拿走停车卡后,系统命令栏杆自动抬起;汽车通过入口后,入口处的传感器通知系统发出命令,栏杆自动放下。3.在停车场内分布着若干个付款机器。驾驶员将在入口处获取的停车卡插入付款机器,并缴纳停车费。付清停车费之后,将获得一张出场卡,用于离开停车场。4.当汽车到达出口时,驾驶员将出场卡插入出口处的读卡器。如果这张卡是有效的,系统命令栏杆自动抬起;汽车通过出口后,出口传感器通知系统发出命令,栏杆自动放下。若这张卡是无效的,系统不发出栏杆抬起命令而发出告警信号。5.系统自动记录停车场内空闲的停车位的数量。若停车场当前没有车位,系统将在入口处显示“车位已满”信息。这时,停车卡打印机将不再出卡,只允许场内汽车出场。根据上述描述,采用面向对象方法对其进行分析与设计,得到了如下表所示的类/用例/状态列表、下图(a)所示的用例图、图(b)所示的初始类图以及图(c)所示的描述入口自动栏杆行为的UML状态图。{{B}}类/用例/状态列表{{/B}}
问答题【说明】
以下C++程序的功能是计算三角形、矩形和正方形的面积并输出。程序由4个类组成:类 Triangle、Rectangle和Square分别表示三角形、矩形和正方形:抽象类Figure提供了一个纯虚函数getAxea(),作为计算上述3种图形面积的通用接口。
【C++代码】
#include<iostream>
#include<cmath>
using namespace std;
class Figure{
public:
virtual double getArea()=0;//纯虚函数
};
class Rectangle :{{U}} (1) {{/U}}{
protected:
double height;
double width;
public:
Rectangle(){}
Rectangle(double height, double width){
this->height=height;
this->width=width;
}
double getArea(){
return{{U}} (2) {{/U}};
}
};
class Square:{{U}} (3) {{/U}}{
public:
Square(double width){
{{U}} (4) {{/U}};
}
};
class Triangle:{{U}} (5) {{/U}}{
private:
double la,lb,lc;
public:
Triangle(double la,double lb,double lc){
this->la=la;this->1b=1b;this->lc=lc;
}
double getArea(){
double s=(la+lb+lc)/2.0;
return sqrt(s*(s-la)*(s-lb)*(s-lc));
}
int main()
{
Figure *figures[3]={new Triangle(2,3,3),new Rectangle(5,8), new Square(5)};
for(int i=0;i<3;i++){
cout<<"figures["<<i<<"]area="<<(figures[i])->getArea()<<endl;
}
return 0;
}
问答题【说明】装饰者模式动态地给一个对象添加一些额外的职责,就扩展功能而言,该模式比生成子类方式更加灵活。装饰模式的提出有助于解决滥用继承的问题。例如,一个名叫星巴兹(Starbuzz)的咖啡连锁店提供多种多样的咖啡,最朴素的设计就是采用继承,即设计一个饮料抽象基类Beverage,让不同种类的咖啡HouseBlend、Decaf、Espresso、DarkRoast继承Beverage类,如图13-23所示。Beverage类的cost()方法是抽象方法,每个子类的cost()方法实现即返回具体咖啡种类的价钱,Beverage类的description实例变量由每个子类设置,用来描述该类饮料,Beverage类的getDescription()方法用来返回此描述。客户在点咖啡时还可以要求添加各种各样的调料(Condiment),加入的调料不同所收取的费用也是不同的,让各种加了调料的不同咖啡都继承基类Beverage,当咖啡种类和调料种类很多时,组合种类的数量就会急剧增长,就会发生“类数量爆炸”现象,如图13-24所示。显然,采用这种设计方式会使得代码的维护变得十分困难,可以采用装饰者模式来解决这个问题。软件设计师蝴蝶飞根据装饰者模式的思想设计了如图13-25所示的类图。在图13-25中,将各种调料Milk、Mocha、Soy、Whip作为装饰者来装饰House-Blend、Decal、Espresso、DarkRoast等各种咖啡。下面的Java程序(代码13-6)对应其具体实现。【代码13-6】importjava.io.*;abstractclassBeverage{Stringdescription="UnknownBeverage";publicStringgetDescription(){returndescription;}public{{U}}(1){{/U}}doublecost();}abstractclassCondimentDecorator{{U}}(2){{/U}}Beverage{publicabstractStrmggetDescription();}classDecafextendsBeverage{publicDecaf(){description="DecafCoffee";}publicdoublecost(){return1.05;}}classEspressoextendsBeverage{publicEspresso(){description="Espresso";}publicdoublecost(){return1.99;}}classHouseBlendextendsBeverage{publicHouseBlend(){description="HouseBlendCoffee";}publicdoublecost(){return.89;}}classDarkRoastextendsBeverage{publicDarkRoast(){description="DarkRoastCoffee";}publicdoublecost(){return.99;}}classMochaextendsCondtmentDecorator{Beverage{{U}}(3){{/U}};publicMocha(Beveragebeverage){this.beverage=beverage;}publicStringgetDescription(){returnbeverage.getDescription()+",Mocha";}publicdoublecost(){return.20+beverage.cost();}}ClassSoyextendsCondimentDecorator{Beveragebeverage;publicSoy(Beveragebeverage){this.beverage=beverage;}publicStrillggetDescription(){returnbeverage.getDescription()+",Soy";}publicdoublecost(){return.15+beverage.cost();}}classWhipextendsCondimentDecorator{BeveragebeverageipublicWhip(Beveragebeverage){this.beverage=beverage;}publicStringgetDescrlption(){returnbeverage.getDescription()+",Whip";}publicdoublecost(){return.10+beverage.cost();}}classMilkextendsCondlmentDecorator{Beverligebeverage;publicMilk(Beveragebeverage){this.beverage=beverage;}publicStringgetDescription(){returnbeverage.getDescription()+",Milk";}publicdoublecost(){return.10+beverage.cost();}}publicclassStarbuzzCoffee{publicstaticvoidmain(Sttingargs[]){//订一杯Espresso咖啡,不需要任何调料,打印出它的描述和价钱Beveragebeverage=newEspresso();System.out.println(beverage.getDescription()+"$"+beverage.cost());//订一杯加了两份Macha调料、一份Whip调料的DarkRoast咖啡//并打印出它的描述和价钱Beveragebeverage2=newDarkRoast();beverage2=newMocha(beverage2):beverage2=new{{U}}(4){{/U}}(beverage2);beverage2=newWhip(beverage2);System.out.println(beverage2.getDescription()+"$"+beverage2.cost());//订一杯加了一份Soy调料、一份Mocha调料、一份Whip调料//的HouseBlend咖啡,并打印出它的描述和价钱Beveragebeverage3=newHouseBlend();beverage3=newSoy(beverage3);beverage3=newMocha(beverage3);beverage3=newWhip(beverage3);System.out.println(beverage3.getDescription()+"$"+beverage3.cost());}}【问题1】根据题目叙述,请将上述Java程序代码13-6中的(1)~(4)空填充完整。【问题2】请写出上述程序的输出结果。