2.5.2 笔试题和面试题
试题1.用简单工厂模式设计一个计算器,该计算器可以完成简单的加法和减法运算。
答案:模式结构如图2.21所示。
图2.21 试题1的模式结构
模式中的角色如下。
SimpleFactory:表示简单工厂类。
Operation:表示抽象运算类。
AddOperation:表示加法运算。
SubOperation:表示减法运算。
抽象运算类的示例代码如下。
/// <summary>
/// 抽象运算类
/// </summary>
public abstract class Operation
{
public int numberA;
public int numberB;
public abstract int GetResult();
}
/// <summary>
/// 加法运算
/// </summary>
public class AddOperation : Operation
{
public override int GetResult()
{
return (this.numberA+this.numberB);
}
}
/// <summary>
/// 减法运算
/// </summary>
public class SubOperation : Operation
{
public override int GetResult()
{
return (this.numberA-this.numberB);
}
}
简单工厂类的代码如下。
/// <summary>
/// 简单工厂类
/// </summary>
public class SimpleFactory
{
public static Operation CreateOperation(string operation)
{
Operation o=null;
switch (operation)
{
case "+":
o=new AddOperation();
break;
case "-":
o=new SubOperation();
break;
}
return o;
}
}
客户端的代码如下。
static void Main(string[] args)
{
Operation operation1=SimpleFactory.CreateOperation("+");
operation1.numberA=10;
operation1.numberB=20;
Console.WriteLine("{0}+{1}={2}",operation1.numberA,operation1.numberB,
operation1.GetResult());
Operation operation2=SimpleFactory.CreateOperation("-");
operation2.numberA=10;
operation2.numberB=20;
Console.WriteLine("{0}-{1}={2}",operation2.numberA,operation2.numberB,
operation2.GetResult());
Console.Read();
}
试题2.Kerrigan实例希望实现懒加载(Lazy Load),如何在需要的时候才构造Kerrigan实例?
答案:
/**
* 能应对大多数情况下的单例实现
*/
public class SingletonKerrigan implements Serializable {
private static class SingletonHolder {
/**
* 单例对象实例
*/
static final SingletonKerrigan INSTANCE=new SingletonKerrigan();
}
public static SingletonKerrigan getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* private标注的构造函数用于避免外界直接使用new来实例化对象
*/
private SingletonKerrigan() {
}
/**
* readResolve方法
*/
private Object readResolve() {
return getInstance();
}
}
试题3.某房地产公司欲开发一套房产信息管理系统,根据如下描述选择合适的设计模式进行设计。
(a)该公司有多种房屋类型,如公寓、别墅等,在将来可能会增加新的房型。
(b)销售人员每售出一套房子,主管将收到相应的销售消息。
分析:可以分别选择简单工厂模式与观察者模式。
答案:参考类图如图2.22所示。在类图中,HouseCreator是抽象房屋工厂类,其子类VilladomCreator用于创建别墅(Villadom),子类ApartmentCreator用于创建公寓(Apartment),Villadom和Apartment都是抽象房屋类House的子类,其中应用了简单工厂模式。如果增加新类型的房屋,只需对应增加新的抽象房屋工厂类即可,原有代码无须做任何修改。House类同时是抽象观察目标,子类Villadom和Apartment是具体观察目标,相关人员类Stakeholder是抽象观察者,其子类Manager(主管)是具体观察者,并且实现了在Stakeholder中声明的response()方法。当房屋售出时,房屋的状态(status)将发生变化,在setStatus()方法中调用具体观察者的response()方法,主管将收到相应消息,其中应用了观察者模式。
图2.22 试题3的参考类图
试题4.猫大叫一声,附近的老鼠都拼命逃跑,主人从美梦中惊醒。
要求如下。
(1)要有联动性,老鼠和主人的行为是被动的。
(2)考虑可扩展性,猫的叫声可能引起其他联动效应。
答案:本题可使用观察者模式,参考类图如图2.23所示。
图2.23 试题4的参考类图
代码如下。
import java.util.*;
interface Subject //抽象主题
{
public void addObserver(Observer obs);
public void cry();
}
interface Observer //抽象观察者
{
public void response();
}
class Cat implements Subject //具体主题
{
private ArrayList<Observer> list;
public Cat()
{
list=new ArrayList<Observer>();
}
public void addObserver(Observer obs)
{
list.add(obs);
}
public void cry()
{
System.out.println("猫大叫一声!");
for(Object obj : list)
{
((Observer)obj).response();
}
}
}
class Mouse implements Observer //具体观察者
{
private String name;
public Mouse(String name, Subject subject)
{
this.name=name;
subject.addObserver(this);
}
public void response()
{
System.out.println(this.name+"拼命逃跑!");
}
}
class Master implements Observer //具体观察者
{
private String name;
public Master(String name,Subject subject)
{
this.name=name;
subject.addObserver(this);
}
public void response()
{
System.out.println(this.name+"从美梦中惊醒!");
}
}
class Client //客户端测试类
{
public static void main(String args[])
{
Subject cat=new Cat();
Observer mouse1,mouse2,master;
mouse1=new Mouse("大老鼠",cat);
mouse2=new Mouse("小老鼠",cat);
master = new Master("主人",cat);
cat.cry();
}
}
输出结果如下。
//猫大叫一声!
//大老鼠拼命逃跑!
//小老鼠拼命逃跑!
//主人从美梦中惊醒!
试题5.Windows Media Player和RealPlayer是两种常用的播放器,它们的API结构和调用方法存在区别。现在应用程序需要支持这两种播放器的API,而且在将来可能还需要支持新的播放器API,请问如何设计该应用程序?
答案:本题可使用适配器模式和抽象工厂模式,参考类图如图2.24所示。
图2.24 试题5的参考类图
在该类图中,我们为两种不同的播放器提供了两个具体工厂类MediaPlayerFactory和RealPlayerFactory。其中MediaPlayerFactory作为Windows Media Player播放器工厂,可以创建Windows Media Player的主窗口(MediaPlayerWindow)和播放列表(MediaPlayerList)(为了简化类图,只列出主窗口和播放列表这两个播放器组成元素,实际情况下应包含更多组成元素);RealPlayerFactory作为RealPlayer播放器工厂,创建RealPlayer的主窗口(RealPlayerWindow)和播放列表(RealPlayerList)。此时可以使用抽象工厂模式,客户端针对抽象工厂PlayerFactory编程。如果要增加新的播放器,只需增加一个新的具体工厂来生产新产品族中的产品即可。由于需要调用现有API中的方法,因此还需要使用适配器模式,在具体产品类(如MediaPlayerWindow和MediaPlayerList)中调用Windows Media Player API中的方法,在RealPlayerWindow和RealPlayerList中调用RealPlayer API中的方法,实现对API中方法的适配。此时具体产品(如MediaPlayerWindow、RealPlayerWindow等)充当适配器,而已有的API(如MediaPlayerAPI和RealPlayerAPI)是需要适配的适配者。
试题6.你能说出在标准的JDK库中使用的一些设计模式吗?
答案:装饰设计模式常用于各种Java I/O类中;单例模式常用在运行环节中,如Calendar;工厂模式常用于各种不可变类,如Boolean。Boolean.valueOf和观察者模式常用于Swing和许多事件监听器框架中。
试题7.在Java中单例设计模式是什么?
答案:单例设计模式在整个系统中主要是共享模式。在整个应用程序实例中只保持一个特定的类,这是由模块共享决定的。
试题8.工厂模式主要的优势是什么?你会在哪种情况下使用工厂模式?
答案:工厂模式主要的优势在于当创建对象时可提高封装水平。如果使用工厂模式来创建对象,可以在后期重置最初产品的装置或者无须任何客户层就可实现更先进、更高性能的类。
试题9.举例说明Java中的观察者设计模式有哪些特点。
答案:观察者设计模式基于对象的变化而改变。例如,在天气系统中必须将天气变化的视图呈现给观众。这里天气项目是主体而非不同的观察者。
版权声明:51Testing软件测试网获得人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。