《设计模式》刘伟-实验参考答案.docx
《《设计模式》刘伟-实验参考答案.docx》由会员分享,可在线阅读,更多相关《《设计模式》刘伟-实验参考答案.docx(21页珍藏版)》请在冰点文库上搜索。
《设计模式》刘伟实验参考答案
实验1
1.在某图形库API中提供了多种矢量图模板,用户可以基于这些矢量图创建不同的显示图形,图形库设计人员设计的初始类图如下所示:
Circle
+
+
+
+
+
init()
setColor()
fill()
setSize()
display()
:
void
void
:
void
:
void
:
void
:
Triangle
+
+
+
+
+
init()
setColor()
fill()
setSize()
display()
void
:
:
void
void
:
void
:
void
:
Rectangle
+
+
+
+
+
init()
setColor()
fill()
setSize()
display()
void
:
void
:
:
void
:
void
:
void
Client
在该图形库中,每个图形类(如Circle、Triangle等)的init()方法用于初始化所创建的图形,setColor()方法用于给图形设置边框颜色,fill()方法用于给图形设置填充颜色,setSize()方法用于设置图形的大小,display()方法用于显示图形。
客户类(Client)在使用该图形库时发现存在如下问题:
①由于在创建窗口时每次只需要使用图形库中的一种图形,因此在更换图形时需要修改客户类源代码;
②在图形库中增加并使用新的图形时需要修改客户类源代码;
③客户类在每次使用图形对象之前需要先创建图形对象,有些图形的创建过程较为复杂,导致客户类代码冗长且难以维护。
现需要根据面向对象设计原则对该系统进行重构,要求如下:
①隔离图形的创建和使用,将图形的创建过程封装在专门的类中,客户类在使用图形时无须直接创建图形对象,甚至不需要关心具体图形类类名;
②客户类能够方便地更换图形或使用新增图形,无须针对具体图形类编程,符合开闭原则。
绘制重构之后的类图并说明在重构过程中所运用的面向对象设计原则。
参考答案:
2.使用简单工厂模式设计一个可以创建不同几何形状(Shape),如圆形(Circle)、矩形
(Rectangle)和三角形(Triangle)等的绘图工具类,每个几何图形均具有绘制draw()和擦除erase()
两个方法,要求在绘制不支持的几何图形时,抛出一个UnsupportedShapeException异常,绘制类图并编程模拟实现。
参考答案:
ShapeFactory
createShape(Stringtype):
Shape
+
Circle
+
+
draw()
erase()
:
void
:
void
Triangle
+
+
draw()
erase()
:
void
void
:
Shape
+
+
draw()
erase()
:
void
:
void
Rectangle
+
+
draw()
erase()
:
void
:
void
UnsupportedShapeException
(
+
UnsupportedShapeException
Stringmessage)
3.现需要设计一个程序来读取多种不同类型的图片格式,针对每一种图片格式都设计一个图片读取器(ImageReader),如GIF图片读取器(GifReader)用于读取GIF格式的图片、JPG图片读取器(JpgReader)用于读取JPG格式的图片。
图片读取器对象通过图片读取器工厂ImageReaderFactory来创建,ImageReaderFactory是一个抽象类,用于定义创建图片读取器的工厂方法,其子类GifReaderFactory和JpgReaderFactory用于创建具体的图片读取器对象。
试使用工厂方法模式设计该程序,绘制类图并编程模拟实现。
需充分考虑系统的灵活性和可扩展性。
参考答案:
<<
create
>>
<<
create
>>
GifReaderFactory
createImageReader():
ImageReader
+
ImageReaderFactory
createImageReader():
ImageReader
+
GifReader
+
readImage():
void
ImageReader
+
readImage():
void
JpgReaderFactory
+
createImageReader():
ImageReader
JpgReader
+
readImage():
void
4.某软件公司欲开发一套界面皮肤库,可以对桌面软件进行界面美化。
不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素,其结构如下图所示:
该皮肤库需要具备良好的灵活性和可扩展性,用户可以自由选择不同的皮肤,开发人员可以在不修改既有代码的基础上增加新的皮肤。
试使用抽象工厂模式设计该皮肤库,绘制类图并编程模拟实现。
参考答案:
5.使用单例模式的思想实现多例模式,确保系统中某个类的对象只能存在有限个,例如两个或三个,设计并编写代码实现一个多例类。
参考答案:
Multiton
-array:
Multiton[]
-Multiton()
+getInstance():
Multiton
+random() :
int
多例模式(MultitonPattern)是单例模式的一种扩展形式,多例类可以有多个实例,而且必须自行创建和管理实例,并向外界提供自己的实例,可以通过静态集合对象来存储这些实
例。
多例类Multiton的代码如下所示:
importjava.util.*;
publicclassMultiton
{
//定义一个数组用于存储四个实例
privatestaticMultiton[]array={newMultiton(),newMultiton(),newMultiton(),newMultiton()};
//私有构造函数
privateMultiton()
{
}
//静态工厂方法,随机返回数组中的一个实例
publicstaticMultitongetInstance()
{
}
returnarray[random()];
}
//随机生成一个整数作为数组下标publicstaticintrandom()
{
Dated=newDate();
Randomrandom=newRandom(); intvalue=Math.abs(random.nextInt()); value=value%4; returnvalue;
}publicstaticvoidmain(Stringargs[])
{
Multitonm1,m2,m3,m4; m1=Multiton.getInstance(); m2=Multiton.getInstance(); m3=Multiton.getInstance(); m4=Multiton.getInstance();
System.out.println(m1==m2);
System.out.println(m1==m3);
System.out.println(m1==m4);
}
6.使用单例模式设计一个多文档窗口(注:
在JavaAWT/Swing开发中可使用
JDesktopPane和JInternalFrame来实现),要求在主窗体中某个内部子窗体只能实例化一次,即只能弹出一个相同的子窗体,如下图所示,编程实现该功能。
(注:
用C#或C++实现类似功能也可以)参考答案:
SubFrame
-
frame:
SubFrame
-
+
SubFrame()
getFrame()
:
SubFrame
MyIFListener
MainClass
-
-
-
button
desktopPane
iFrame
:
JButton
:
JDesktopPane
:
SubFrame
+
()
MainClass
BtListener
SubFrame类充当单例类,在其中定义了静态工厂方法getFrame()。
代码如下所示:
importjava.awt.*;importjava.awt.event.*;importjavax.swing.*;importjavax.swing.event.*;
//子窗口:
单例类
classSubFrameextendsJInternalFrame
{
privatestaticSubFrameframe;//静态实例
//私有构造函数
privateSubFrame()
{ super("子窗体",true,true,true,false); this.setLocation(20,20);//设置内部窗体位置 this.setSize(200,200);//设置内部窗体大小
this.addInternalFrameListener(newMyIFListener());//监听窗体事件 this.setVisible(true);
}
//工厂方法,返回窗体实例
publicstaticSubFramegetFrame(){
//如果窗体对象为空,则创建窗体,否则直接返回已有窗体
if(frame==null)
{ frame=newSubFrame();
}
returnframe;
}
//事件监听器
classMyIFListenerextendsInternalFrameAdapter{
//子窗体关闭时,将窗体对象设为null
publicvoidinternalFrameClosing(InternalFrameEvente)
{
if(frame!
=null)
{
frame=null;
}
}
}
}
//客户端测试类
classMainClassextendsJFrame
{ privateJButtonbutton; privateJDesktopPanedesktopPane; privateSubFrameiFrame=null;
publicMainClass()
{
super("主窗体");
Containerc=this.getContentPane(); c.setLayout(newBorderLayout());
button=newJButton("点击创建一个内部窗体"); button.addActionListener(newBtListener()); c.add(button,BorderLayout.SOUTH);
desktopPane=newJDesktopPane();//创建DesktopPane c.add(desktopPane);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLocationRelativeTo(null); this.setSize(400,400); this.show();
}
//事件监听器
classBtListenerimplementsActionListener
{ publicvoidactionPerformed(ActionEvente)
{
if(iFrame!
=null)
{
desktopPane.remove(iFrame);
}
iFrame=SubFrame.getFrame(); desktopPane.add(iFrame);
}
}publicstaticvoidmain(String[]args)
{ newMainClass();
}
}
SubFrame类是JInternalFrame类的子类,在SubFrame类中定义了一个静态的SubFrame类型的实例变量,在静态工厂方法getFrame()中创建了SubFrame对象并将其返回。
在MainClass类中使用了该单例类,确保子窗口在当前应用程序中只有唯一一个实例,即只能弹出一个子窗口。
实验2
1.现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法,类BinarySearch的binarySearch(int[],int)方法实现了二分查找算法。
试使用适配器模式设计一个系统,在不修改源代码的情况下将类QuickSort和类BinarySearch的方法适配到DataOperation接口中。
绘制类图并编程实现。
(要求实现快速排序和二分查找,使用对象适配器实现)参考答案:
OperationAdapter
-
-
sortObj
searchObj
QuickSort
:
:
BinarySearch
+
+
+
OperationAdapter(QuickSortsortObj,
BinarySearchsearchObj)
sort(intarray[])
search(intarray[],intkey)
:
[]
int
:
int
DataOperation
+
+
sort(intarray[])
search(intarray[],intkey)
int
[]
:
:
int
QuickSort
+
+
+
+
quickSort(intarray[])
sort(intarray[],intp,intr)
partition(inta[],intp,intr)
swap(inta[],inti,intj)
[]
int
:
void
:
int
:
void
:
BinarySearch
+
binarySearch(intarray[],intkey):
int
Client
2.WindowsMediaPlayer和RealPlayer是两种常用的媒体播放器,它们的API结构和调用方法存在区别。
现在你的应用程序需要支持这两种播放器API,而且在将来可能还需要支持新的媒体播放器,请问如何设计该应用程序?
绘制类图并编程模拟实现。
参考答案:
可使用适配器模式和抽象工厂模式,参考类图如下所示:
MediaPlayerWindow
MainWindow
MediaPlayerFactory
+
+
createMainWindow()
createPlayerList()
MainWindow
:
PlayerList
:
PlayerFactory
+
+
createMainWindow()
createPlayerList()
:
MainWindow
:
PlayerList
ClientClass
RealPlayerFactory
+
+
createMainWindow()
createPlayerList()
MainWindow
:
:
PlayerList
RealPlayerWindow
MediaPlayerList
PlayerList
RealPlayerList
MediaPlayerAPI
RealPlayerAPI
在该类图中,为两种不同的播放器提供了两个具体工厂类MediaPlayerFactory和
RealPlayerFactory,其中MediaPlayerFactory作为WindowsMediaPlayer播放器工厂,可以创建WindowsMediaPlayer的主窗口(MediaPlayerWindow)和播放列表(MediaPlayerList)(为了
简化类图,只列出主窗口和播放列表这两个播放器组成元素,实际情况下包含更多组成元素);RealPlayerFactory作为RealPlayer播放器工厂,创建RealPlayer的主窗口(RealPlayerWindow)和播放列表(RealPlayerList),此时可以使用抽象工厂模式,客户端针对抽象工厂PlayerFactory编程,如果增加新的播放器,只需增加一个新的具体工厂来生产新产品族中的产品即可。
由于需要调用现有API中的方法,因此还需要使用适配器模式,在具体产品类如MediaPlayerWindow和MediaPlayerList调用WindowsMediaPlayerAPI中的方法,在RealPlayerWindow和RealPlayerList中调用RealPlayerAPI中的方法,实现对API中方法的适配,此时具体产品如MediaPlayerWindow、RealPlayerWindow等充当适配器,而已有的API如MediaPlayerAPI和RealPlayerAPI是需要适配的适配者。
3.使用组合模式设计一个杀毒软件(AntiVirus)的框架,该软件既可以对某个文件夹
(Folder)杀毒,也可以对某个指定的文件(File)进行杀毒,文件种类包括文本文件TextFile、图片文件ImageFile、视频文件VideoFile。
绘制类图并编程模拟实现。
参考答案:
fileList
AbstractFile
{
abstract}
+
+
+
+
add(AbstractFilefile)
remove(AbstractFilefile)
getChild(inti)
killVirus()
void
:
:
void
AbstractFile
:
:
void
ImageFile
name:
String
-
+
+
+
+
+
ImageFile(Stringname)
add(AbstractFilefile)
remove(AbstractFilefile)
getChild(inti)
killVirus()
void
:
:
void
AbstractFile
:
void
:
Folder
-
-
fileList
name
ArrayList
:
String
:
+
+
+
+
+
Folder(Stringname)
add(AbstractFilefile)
remove(AbstractFilefile)
getChild(inti)
killVirus()
:
void
void
:
:
AbstractFile
:
void
TextFile
-
name:
String
+
+
+
+
+
TextFile(Stringname)
add(AbstractFilefile)
remove(AbstractFilefile)
getChild(inti)
killVirus()
void
:
:
void
AbstractFile
:
void
:
VideoFile
name:
String
-
+
+
+
+
+
VideoFile(Stringname)
add(AbstractFilefile)
remove(AbstractFilefile)
getChild(inti)
killVirus()
void
:
:
void
:
AbstractFile
void
:
4.某教育机构组织结构如下图所示:
北京总部
教务办公室
湖南
分校
行政办公室
长沙教学点
湘潭教学点
教务办公室
行政办公室
教务办公室
行政办公室
教务办公室
行政办公室
在该教育机构的OA系统中可以给各级办公室下发公文,试采用组合模式设计该机构的组织结构,绘制相应的类图并编程模拟实现,在客户端代码中模拟下发公文。
参考答案:
参考类图如下所示:
list
Unit
{
abstract}
+
handleArchives():
void
Office
name:
String
-
+
+
Office(Stringname)
handleArchives()
:
void
Institution
-
-
list
name
:
ArrayList
:
String
+
+
+
Institutio