5种常用设计模式——软件测试工程师面试秘籍(19)

发表于:2021-12-17 09:10

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:G.li    来源:51Testing软件测试网原创

  2.5  设计模式
  2.5.1  5种常用设计模式
  考点:5种常用设计模式的理论理解和实际应用。

  1.简单工厂模式
  简单工厂模式的优点是,工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
  客户端实例化对象时不需要关心该对象是由哪个子类实例化的。简单工厂模式的结构如图2.18所示。
图2.18  简单工厂模式的结构

  简单工厂模式中的角色如下。
  IProduct接口:表示抽象产品类。
  ConcreteProduct类:表示产品类的具体实现。
  Simple Factory:表示简单工厂类。
  简单工厂模式的本质在于为客户端选择相应的实现,从而使客户端和实现方式之间解耦。其优缺点如下。
  优点:帮助封装,解耦,通过简单工厂类实现客户端和具体实现类的解耦。
  缺点:可能增加客户端的复杂度,不方便扩展子工厂。
  举例如下。
  Api接口的实现如下:
[java] view plaincopy
package com.examples.pattern.simpletFactory;  
  
public interface Api{  
      
    public void operation(String s);  
  
}

  Impl类的实现如下:
[java] view plaincopy
 package com.examples.pattern.simpletFactory;  
   
 public class Impl implements Api{  
   
     @Override  
     public void operation(String s){  
         System.out.println(">>>>>>>>>>>>>>"+s);  
     }  
   
}

  Factory类的实现如下:
[java] view plaincopy
package com.examples.pattern.simpletFactory;  
  
public class Factory{  
      
    public Api createApi(){  
        return new Impl();  
    }  
  
}

  Client类的实现如下:
[java] view plaincopy
 package com.examples.pattern.simpletFactory;  
   
 public class Client{  
   
     public static void main(String[] args){  
         Api api = new Factory().createApi();  
         api.operation("测试简单工厂模式…… ");  
     }  
   
}

  2.单例模式
  单例模式可以是很简单的,它只需要一个类就可以完成。但是如果考虑对象创建的次数及何时被创建,单例模式可以相当复杂,如涉及双锁检测(Double Checked Locking,DCL)的讨论、多个类加载器(ClassLoader)协同、跨JVM(集群、远程EJB等)、单例对象被销毁后重建等。
  对于系统中的某些类来说,只有一个实例很重要。例如,一个系统中可以存在多个输出任务,但是只能有一个正在处理的任务,一个系统中只能有一个窗口管理器或文件系统,一个系统只能有一个计时工具或ID(序号)生成器。例如,在Windows操作系统中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口。如果这些窗口显示的内容完全一致,则说明定义了多个对象,浪费了内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,并且会给用户带来误解,让用户不知道哪一个才是真实的状态。因此,有时确保系统中某个对象的唯一性(一个类只能有一个实例)非常重要。
  如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的设计动机。
  显然,单例模式的特点有三个。
  某个类只能有一个实例。
  类必须自行创建这个实例。
  类必须自行向整个系统提供这个实例。
  单例模式的优点如下。
  实例控制:单例模式会阻止其他对象实例化自己的单例对象的副本,从而确保所有对象都访问唯一实例。
  灵活性:因为类控制了实例化过程,所以类可以灵活更改实例化过程。
  单例模式的缺点如下。
  开销较大:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,仍然需要一些开销。可以通过使用静态初始化解决此问题。
  可能的开发混淆:使用单例对象(尤其在类库中定义的对象)时,开发人员不能使用new关键字实例化对象。因为可能无法访问库源代码,所以应用程序开发人员可能会意外发现自己无法直接实例化此类。
  对象生存期:不能解决删除单个对象的问题。在提供内存管理的语言(如基于.NET Framework的语言)中,只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言(如C++)中,其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。

  3.观察者模式
  观察者模式有时称为发布/订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。该主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
  将一个系统分割成一些相互协作的类有一个副作用—需要维护相关对象间的一致性。我们不希望为了维护一致性而使各类紧密耦合,因为这样会给维护、扩展和重用类都带来不便。观察者模式就是解决这类耦合关系的。
  观察者模式的模块关系如图2.19所示。
图2.19  观察者模式的模块关系

  模式中的角色如下。
  抽象主题(Subject):把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
  具体主题(Concrete Subject):将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
  抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
  具体观察者(Concrete Observer):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
  观察者模式的优缺点如下。
  优点:解除了主题和具体观察者的耦合,让耦合的双方都依赖抽象事物,而不是依赖具体事物,从而使得各自的变化都不会影响另一边的变化。
  缺点:依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
  观察者模式的适用场景如下。
  一个对象的改变造成其他对象的改变,而且这个对象不知道具体有多少个对象有待改变。
  一个抽象模型有两个方面,当其中一个方面依赖于另一个方面时,用观察者模式可以将这两者封装在独立的对象中,使它们各自独立地改变和复用。

  4.命令模式
  命令模式将一个请求封装成一个对象,从而可以使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。对于大多数请求-响应模式的功能,比较适合使用命令模式。命令模式有助于实现记录日志、撤销操作等。命令模式的基本结构如图2.20所示。
图2.20  命令模式的基本结构

  顾名思义,命令模式就是对命令的封装。命令模式中的角色如下。
  Command类:一个抽象类,类中对需要执行的命令进行声明,一般来说,要对外公布一个execute()方法,用来执行命令。
  ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现。
  Client类:最终的客户端调用类。
  命令模式的优点如下。
  首先,命令模式的封装性很好。每个命令都被封装起来,对于客户端来说,需要什么功能就调用相应的命令,而无须知道命令具体是怎么执行的。例如,有一组文件操作命令,用于新建文件、复制文件、删除文件。如果把这3个操作都封装成一个命令类,则客户端只需要知道有这3个命令类即可,至于命令类中封装好的逻辑,客户端无须知道。
  其次,命令模式的扩展性很好。在命令模式中,在Receiver类中一般会对操作进行基本的封装,Command类则通过对这些基本的操作进行两次封装。当增加新命令时,对命令类的编写一般不是从零开始的,有大量的接收者类可供调用,也有大量的命令类可供调用,代码的可复用性很高。例如,文件操作中,如果要增加一个剪切文件的命令,则只需要把复制文件和删除文件这两个命令进行组合即可。
  命令模式的缺点就是如果命令很多,开发起来会较困难。特别是很多简单的命令,实现起来几行代码即可,而如果使用命令模式,无论命令多简单,都需要写命令类来封装。

  5.适配器模式
  适配器模式将一个类的接口转换成客户端希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
  适配器模式中的角色如下。
  目标接口:客户端所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
  需要适配的类:需要适配的类或适配者类。
  适配器:通过包装一个需要适配的对象,把原接口转换成目标接口。
  适配器模式的优点如下。
  (1)通过适配器,客户端可以调用同一接口,因此对客户端来说适配器是透明的。
  (2)复用了现存的类,解决了现存类和复用环境要求不一致的问题。
  (3)将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无须修改原有代码。
  (4)一个对象适配器可以把多个不同的适配者类适配到同一个目标,即同一个适配器可以把适配者类和它的子类都适配到目标接口。
  适配器模式缺点是对于对象适配器来说,更换适配器的实现过程比较复杂。
  适配器模式的使用场景如下。
  (1)系统需要使用现有的类,而这些类的接口不符合系统的接口。
  (2)要建立一个可以重用的类,用于与一些彼此之间没有太大关联的类(包括一些可能在将来引进的类)一起工作。
  (3)两个类所做的事情相同或相似,但是具有不同接口。
  (4)旧的系统开发的类已经实现了一些功能,客户端却只能以其他接口的形式访问,但我们不希望手动更改原有类。
  (5)需要使用第三方组件。组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。

查看《软件测试工程师面试秘籍》全部连载章节
版权声明:51Testing软件测试网获得人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号