问题 问答题

【说明】
有时我们希望给某个对象而不是整个类添加一些功能。例如,一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性,例如边框,或是一些行为,例如窗口滚动。使用继承机制是添加功能的一种有效途径,从其他类继承过来的边框特性可以被多个子类的实例所使用。但这种方法不够灵活,因为边框的选择是静态的,用户不能控制对组件加边框的方式和时机。
一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加边框。我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。它将客户请求转发给该组件,并且可能在转发前后执行一些额外的动作(例如画二个边框)。透明性使得你可以递归地嵌套多个装饰,从而可以添加任意多的功能。
装饰对象结构模式的意图就是动态地给一个对象添加一些额外的职责。就增加功能来说,该模式相比生成子类更为灵活。其示意类图如图13-22所示。


程序代码13-5是该模式的一个示例,说明了如何实现用户接口装饰,函数的实现全部省略。程序中定义了VisualComponent的一个子类Decorator,我们将生成Decorator的子类以获取不同的装饰。VisualComponent类是一个描述可视对象的抽象类,它描述了绘制和事件处理的接口。Decorator的子类定义了特殊的装饰功能,BorderDecorator子类给可视组件添加一个边框,ScrollDecorator给可视组件添加滚动功能。
【程序代码13-5】
(1)
class Window

public:
roid SetContents (VisualComponent * contents);

//VisualComponent类是一个描述可视对象的抽象类
class VisllalComponent

public:
VisualComponent();
(2) void Draw();
Virtual void Resize();

class Decorator:public VisualComponent

public:
Decorator()

//…

Decorator(VisualComponent * vcom)

//…

virtual vold Draw();
virtual vold Resize();
private:
/* Decorator装饰由VisualComponent的指针实现,其在Decorator的构造函数中初始化*/
VisualComponent (3)

vold Decorator::Draw()

(4) ;//缺省实现

void Decorator::Resize()

component->Resize();//缺省实现

//BorderDecorator 子类为它所包含的组件添加一个边框
class BorderDecorator:public Decorator

public:
BorderDecorator(VisualComponent * vcom,int borderWidth)

//…

Virtual Void Draw();
private:
void DrawBorder(int);
private:
int borderWidth;

void BorderDecorator::Draw()

Decorator::Draw();
DrawBorder(_width);

Void BorderDecorator::DrawBorder(int Width)

//…
)
Void Window::SetConterlts(VlsualComponent * contents)

//…

//SerollDecorat 给可视组件添加滚动功能
class ScroliDecoratOr:public Decorator

public:
ScrollDecorator(VlsualComponent * vcom)

//…

//…
);
class TextView:public VisualComponent

//…

void main(void)

//创建一个正文视图以及放入这个正文视图的窗口
Window * window=new Window;
TcxtView * textView=new TextView;
//TextView是一个VisualComponent,它可以放入窗口中
window->SetContents(textView);
//得到一个有边界的和可以滚动的TextView,边界宽为1
window->SetContents( (5) );

答案

参考答案:(1)class VisualComponent (2)virtual
(3)* component (4)component->Draw()
(5)new BorderDecorator(new ScrollDecorator(textView),1)

解析:装饰者模式适合以下情况:
(1)在不影响其它对象的情况下,以动态、透明的方式给单个对象添加职责。
(2)处理那些可以撤消的职责。
(3)当不能采用生成子类的方法进行扩充时,有两种情况:一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;另一种情况可能是,因为类定义被隐藏,或类定义不能用于生成子类。
题目给出的程序代码以如何获得一个带边框和滚动条的正文视图窗口为例说明了该模式,其中的具体实现全部省略。题中给出的示意类图是该模式通用的结构示意。程序代码涉及的类结构如图13-53所示。
[*]
其中,ScrollDecorator、BorderDecorator分别相当于题目中通用结构图中的ConcreteDecoratorA、 ConcreteDecoratorB,它们的职责就是向组件添加相应的功能。
程序代码中,Decorator装饰由VisualComponent的指针component实现,对于Visual Component接口中定义的每一个操作,Decorator类都定义了一个缺省的实现,这一实现将相关请求转发给component,因此第(3)、(4)空分别填:* component、component-> Draw()。
类VisualComponent在Window之后定义,而在Window类中使用了VisualComponent类,所以先要声明该类,因此,第(1)空填:class VisualComponent。VisualComponent类是个抽象类,它是一个界面,它的方法应声明为虚函数,具体实现交由其子类实现,因此,第(2)空填:virtual。
第(5)空有点难度,根据注释“TextView是一个VisualComponent,它可以放入窗口中”可知,Window的方法SetContents参数是一个VisualComponent对象,现需要获得一个有边界的和可以滚动的TextView,边界宽为1,因此要创建一个新的ScrollDecorator对象,将textView放入其中,然后以其为第一个参数构造一个BorderDecorator对象,然后把这个BorderDecorator对象放入到窗口中去即可,因此,该空应填:new BorderDecorator (new ScrollDecorator(textView),1)。

问答题

[背景资料]
某水利工程施工项目,项目法人依据《水利水电土建工程施工合同条件》(GF——2000——0208),与施工单位签订了施工合同。招标文件中的工期为280天,协议书中的工期为240天。
施工中发生了下列事件:
事件一:施工单位在按监理单位签发的设计文件组织施工前,发现某部位钢筋混凝土浇筑要求与相关规范规定不一致,向设计单位提出变更建议并附变更方案;设计单位审核后认为施工单位的建议正确、方案合理,向施工单位发出了设计修改文件。
事件二:在施工过程中,根据监理单位的书面指示,施工单位进行了跨河公路桥基础破碎岩石开挖,但公路桥报价清单中无此项内容。主体工程报价清单中有以下单价:
(1)混凝土坝A:砂卵石、岩石地基开挖70元/m3;B:基础处理80元/m3
(2)土石坝C:砂卵石、岩石地基开挖50元/m3;D:基础处理60元/m3
事件三:施工单位经监理单位批准后,对基础进行了混凝土覆盖。在下一仓浇筑准备时,监理单位对已覆盖的基础质量有疑问,指示施工单位剥离已浇混凝土并重新检验。检测结果表明,基础质量不合格。施工单位按要求进行返工处理并承担了相应的施工费用,但提出了检验费用支付申请和因此次检验影响进度的工期索赔。

在事件二中,如果从4个单价中选用,你认为哪一项单价最为合理说明理由。

判断题