一. 单选题(共6题)

  1. (单选题)在享元模式中,外部状态是指( )。 A. 享元对象可共享的所有状态 B. 享元对象可共享的部分状态 C. 由享元对象自己保存和维护的状态 D. 由客户端保存和维护的状态 我的答案: D:由客户端保存和维护的状态;正确答案: D:由客户端保存和维护的状态;

  1. (单选题)以下关于享元模式的叙述错误的是( )。 A. 享元模式运用共享技术有效地支持大量细粒度对象的复用 B. 在享元模式中可以多次使用某个对象,通过引入外部状态使得这些对象可以有所差异 C. 享元对象能够做到共享的关键是引入了享元池,在享元池中通过克隆方法向客户端返回所需对象 D. 在享元模式中,外部状态是随环境改变而改变、不可以共享的状态,而内部状态是不随环境改变而改变、可以共享的状态 我的答案: C:享元对象能够做到共享的关键是引入了享元池,在享元池中通过克隆方法向客户端返回所需对象;正确答案: C:享元对象能够做到共享的关键是引入了享元池,在享元池中通过克隆方法向客户端返回所需对象;

  1. (单选题)为了节约系统资源,提高程序的运行效率,某系统在实现数据库连接池时可以使用( )设计模式。 A. 外观(Facade) B. 原型(Prototype) C. 代理(Proxy) D. 享元(Flyweight) 我的答案: D:享元(Flyweight);正确答案: D:享元(Flyweight);

  1. (单选题)毕业生通过职业介绍所找工作,该过程蕴含了( )模式。 A. 外观(Facade)
    B. 命令(Command) C. 代理(Proxy)
    D. 桥接(Bridge) 我的答案: C:代理(Proxy) ;正确答案: C:代理(Proxy) ;

  1. (单选题)代理模式有多种类型,其中智能引用代理是指( )。 A. 为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果 B. 保护目标不让恶意用户接近 C.使几个用户能够同时使用一个对象而没有冲突 D. 当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来 我的答案: D:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来;正确答案: D:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来;

  1. (单选题)以下关于代理模式的叙述错误的是( )。 A. 代理模式能够协调调用者和被调用者,从而在一定程序上降低系统的耦合度 B. 控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限时可以考虑使用远程代理 C. 代理模式的缺点是请求的处理速度会变慢,并且实现代理模式需要额外的工作 D. 代理模式给某一个对象提供一个代理,并由代理对象控制对原对象的引用 我的答案: B:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限时可以考虑使用远程代理;正确答案: B

二. 填空题(共2题)

  1. (填空题)某软件公司欲开发一个多功能文本编辑器,在文本中可以插入图片、动画、视频等多媒体资料,为了节约系统资源,使用享元模式设计该系统,所得类图如图1所示: image.png ::: hljs-center

图1 类图

:::

在图1中,MultimediaFile表示抽象享元,其子类Image、Animation和Video表示具体享元。对于相同的多媒体文件,其大小Size和位置Location可以不同,因此需要通过Setter方法来设置这些外部状态。MultimediaFileFactory是享元工厂,在其中定义一个Hashtable对象作为享元池,存储和维护享元对象。

【Java代码】
import java.util.*;
//位置类:外部状态类
class Location
{
 private int x;
 private int y;
 public Location(int x,int y)
 {
 this.x = x;
 this.y = y;
 }
 //Getter方法和Setter方法省略
}
//大小类:外部状态类
class Size
{
 private int width;
 private int height;
 public Size(int width,int height)
 {
 this.width = width;
 this.height = height;
 }
 //Getter方法和Setter方法省略
}
//多媒体文件类:抽象享元类
        (1)          MultimediaFile
{
 protected Size size;
 protected Location location;
 public abstract void display();
 public void setSize(Size size)
 {
 this.size = size;
 }
 public void setLocation(Location location)
 {
 this.location = location;
 }
}

//图片文件类:具体享元类
class Image extends MultimediaFile
{
 private String fileName;
 public Image(String fileName)
 {
 this.fileName = fileName;
 }
 public void display()
 {
 //导入和显示图片文件代码省略,在显示图片时将使用size和location对象
 }
}

//动画文件类:具体享元类
class Animation extends MultimediaFile
{    //动画文件类代码省略    }
//视频文件类:具体享元类
class Video extends MultimediaFile
{    //视频文件类代码省略    }
//多媒体文件工厂类:享元工厂类
class MultimediaFileFactory
{
 private Hashtable ht;  //享元池
 private int fileNum = 0;  //享元对象计数器
 public MultimediaFileFactory()
 {
 ht =         (2)         ;
 }
 //从享元池中获取对象
 public         (3)         getMultimediaFile(String fileName)
 {
 //根据文件后缀名判断文件类型
 String[] strArray = fileName.split("\\.");
 int ubound = strArray.length;
 String extendName = strArray[ubound-1];

 if(ht.containsKey(fileName))
 {
 return (MultimediaFile)        (4)         ;
 }
 else
 {
 if(extendName.equalsIgnoreCase("gif")||extendName.equalsIgnoreCase("jpg"))
 {
 MultimediaFile file = new Image(fileName);
 ht.put(fileName,file);
 fileNum++;
 }
 else if(extendName.equalsIgnoreCase("swf"))
 {
 MultimediaFile file = new Animation(fileName);
 ht.put(fileName,file);
         (5)         ;
 }
 //其他代码省略
 } 
 }

 //返回享元对象数量
 public int getFileNum()
 {
 return fileNum;
 }
}
class Test
{
 public static void main(String args[])
 {
 MultimediaFile file1,file2,file3,file4;
 MultimediaFileFactory factory;
 factory = new MultimediaFileFactory();
 
 file1 = factory.getMultimediaFile("sun.jpg");
 file1.setSize(new Size(300,400));
 file1.setLocation(new Location(3,5));
 file2 = factory.getMultimediaFile("sun.jpg");
 file2.setSize(new Size(300,400));
 file2.setLocation(new Location(6,5));
 file3 = factory.getMultimediaFile("star.swf");
 file3.setSize(new Size(200,200));
 file3.setLocation(new Location(10,1)); 
 file4 = factory.getMultimediaFile("moon.swf");
 file4.setSize(new Size(400,400));
 file4.setLocation(new Location(15,2)); 
 System.out.println(file1==file2);   //输出语句1
 System.out.println(factory.getFileNum());    //输出语句2
 }
}

在Test类中,“输出语句1”输出结果为 (6) ,“输出语句2”输出结果为 (7) 。

正确答案: (1) abstract class (2) new Hashtable() (3) MultimediaFile (4) ht.get(fileName) (5) fileNum++ (6) true (7) 3


  1. 某信息咨询公司推出收费的在线商业信息查询模块,需要对查询用户进行身份验证并记录查询日志,以便根据查询次数收取查询费用,现使用代理模式设计该系统,所得类图如图1所示: image.png 在图1中,AccessValidator类用于验证用户身份,它提供方法validate()来实现身份验证;Logger类用于记录用户查询日志,它提供方法log()来保存日志;RealSearcher类实现查询功能,它提供方法doSearch()来查询信息。ProxySearcher作为查询代理,维持对RealSearcher对象、AccessValidator对象和Logger对象的引用。
【Java代码】
class AccessValidator
{
 public boolean validate(String userId)
 {
 //身份验证实现代码省略
 }
}

class Logger
{
 public void log(String userId)
 {
 //日志记录实现代码省略
 }
}

interface Searcher
{
 public String doSearch(String userId,String keyword);
}

class RealSearcher implements Searcher
{
 public String doSearch(String userId,String keyword)
 {
 //信息查询实现代码省略
 }
}

class ProxySearcher        (1)        
{
 private RealSearcher searcher = new RealSearcher();
 private AccessValidator validator;
 private Logger logger;
 
 public String doSearch(String userId,String keyword)
 {
 //如果身份验证成功,则执行查询
 if(     (2)     )
 {
 String result = searcher.doSearch(userId,keyword);
      (3)      ; //记录查询日志
      (4)     ; //返回查询结果
 }
 else
 {
 return null;
 }
 } 

 public boolean validate(String userId)
 {
 validator = new AccessValidator();
        (5)      ;
 }

 public void log(String userId)
 {
 logger = new Logger();
       (6)      ;
 }
}

class Test
{
 public static void main(String args[])
 {
       (7)       ;  //针对抽象编程,客户端无须分辨真实主题类和代理类
 searcher = new ProxySearcher();
 String result = searcher.doSearch("Sunny","Money");
 //此处省略后续处理代码
 }
}

正确答案: (1) implements Searcher (2) validate(userId) (3) log(userId) (4) return result (5) return validator.validate(userId) (6) logger.log(userId) (7) Searcher searcher


三. 简答题(共2题) 9. 使用享元模式设计一个围棋软件,在系统中只存在一个白棋对象和一个黑棋对象,,但是它们可以在棋盘的不同位置显示多次。要求使用简单工厂模式和单例模式实现享元工厂类的设计。客户端要求获取3个黑子对象和2个白子对象,并显示它们在棋盘上的不同位置。

(1)画出UML类图 image.png (2)使用Java语言编程实现

public class Client {
   public static void main(String[] args) {
       PlayChess black1,black2,black3,white1,white2;
       black1 = PlayChessFactory.getPlayChess("b");
       black1.locate(new Checkerboard(1,2));
       black2 = PlayChessFactory.getPlayChess("b");
       black2.locate(new Checkerboard(3,4));
       black3 = PlayChessFactory.getPlayChess("b");
       black3.locate(new Checkerboard(1,3));

       white1 = PlayChessFactory.getPlayChess("w");
       white1.locate(new Checkerboard(2,4));
       white2 = PlayChessFactory.getPlayChess("w");
       white2.locate(new Checkerboard(2,5));
   }
}

=========================================

public abstract class PlayChess {
   public abstract String getColor();
   public void locate(Checkerboard coord){
       System.out.println("棋子颜色:"+this.getColor()+",棋子位置:"+coord.getX()+","+coord.getY());
   }
}

public class BlackPlayChess extends PlayChess {
   public String getColor(){
       return "黑色";
   }
}

public class WhitePlayChess extends PlayChess {
   public String getColor(){
       return "白色";
   }
}

public class PlayChessFactory {
   private static PlayChessFactory instance = new PlayChessFactory();
   private static Hashtable hashtable;

   private PlayChessFactory(){
       hashtable = new Hashtable();
       PlayChess black,white;
       black = new BlackPlayChess();
       hashtable.put("b", black);
       white = new WhitePlayChess();
       hashtable.put("w",white);
   }
   public static PlayChessFactory getInstance(){
       return instance;
   }
   public static PlayChess getPlayChess(String color){
       return (PlayChess) hashtable.get(color);
   }
}

=========================================

public class Checkerboard {
   private int x;
   private int y;
   public Checkerboard(int x, int y){
       this.x=x;
       this.y=y;
   }

   public int getX() {
       return x;
   }

   public void setX(int x) {
       this.x = x;
   }

   public int getY() {
       return y;
   }

   public void setY(int y) {
       this.y = y;
   }
}

(3)运行效果图 image.png


  1. (简答题) 应用软件所提供的桌面快捷方式是快速启动应用程序的代理,桌面快捷方式一般使用一张小图片来表示(Picture),通过调用快捷方式的run()方法将调用应用软件(Application)的run()方法。使用代理模式模拟该过程。 (1)画出UML类图 image.png (2)使用Java语言编程模拟实现
public interface App {
   void run();
}

public class Application implements App {
   @Override
   public void run() {
       System.out.println("App启动中");
   }
}

public class Picture implements App {
   private Application app=new Application();
   @Override
   public void run() {
       System.out.println("点击图片打开软件!");
       app.run();
   }
}

public class Client {
   public static void main(String[] args) {
       App appProxy=new Picture();
       appProxy.run();
   }
}

(3)运行效果图 image.png