当前位置:文档之家› 通过代码示例学习GOF 设计模式(第13章适配器模式)

通过代码示例学习GOF 设计模式(第13章适配器模式)

通过代码示例学习GOF 设计模式(第13章适配器模式)
通过代码示例学习GOF 设计模式(第13章适配器模式)

前言

软件开发工作从本质上属于创造性的工作,它是一种将“软件产品”从无到有生的创建过程。行业内流行的“站在巨人的肩膀上”、“不要重复地发明轮子”、“不要不断地重复自己”等“名言警句”其实都是对“软件复用”思想的具体体现。

面向对象程序设计方法提供了类级别的重用;而基于“组件化”的复用方式,已使软件系统产品在质量保证、开发效率等方面得到了更大的提高;面向框架级的系统集成开发(如J2EE中的SSH、https://www.doczj.com/doc/089327608.html,、PHP的LAMP等),不仅可以实现组件级别的重用,而且在系统的总体架构、软件设计思想等方面都可以得到重用。因此“面向对象”、“组件化”、“基于XML的数据结构描述”、“面向框架”等设计思想和实现技术,更使得软件系统的“复用”达到了一个更深的层次,随之而来的各种企业级“中间件组件”、AOP、SOA等技术的出现,也使得开发者的主要精力可以越来越多地关注于应用系统的业务逻辑和业务数据,而非系统“底层”的具体实现技术和各个不同技术平台之间、各个数据库系统之间的差异。

作者接触很多高校计算机软件专业类的教师和学生,深感目前的计算机软件开发类专业的程序设计类各个课程在教学方面的欠缺,不仅编码不规范(胡写代码和混乱命名)、技术深度不足(学C语言不学习指针、学Java不学习集合、反射和范型),而且程序代码还存在许多不可靠、性能低下、扩展性差等方面的问题;国内许多“小作坊”型的软件公司人员不断地生产出大量的“垃圾代码”,从而使得这些软件公司的项目都是“一次性买卖”,客户方受骗后再也没有第二次的项目开发。

作者根据自身多年的软件开发实践和经验总结,结合多年的IT职业培训的教学和高校软件学院一线的教学工作体验,在本系列文档中通过具体的程序代码示例为读者介绍GOF 设计模式及相关的应用技术。主要的目的是希望能够以成功的经验或者失败的教训为读者减少软件开发失败的风险,同时也为高校师生总结出如何能够编程开发出一个“易读的”、“易维护的”、“易扩展”、“高性能”和“可重用”的系统程序。

本文档主要涉及GoF适配器模式及应用、适配器模式主要技术特性和程序结构,适配器模式的应用示例、类适配器的应用示例、对象适配器的应用示例和如何应用适配器模式实现组合转换器的应用实例等方面的内容。

杨教授大学堂精心创作有系列化的优秀程序员职业提升必读技术资料,这些资料将系统地从软件设计和开发实现的“设计思想”、“管理策略”、“技术实现”和“经验方法”等方面与读者进行充分的交流,涉及作者对软件开发设计思想和原则、课程设计、项目实训、软件实现技术等方面的学习心得体会和应用技巧、经验总结。

本文目录

1.1GoF适配器模式及应用 (3)

1.1.1GoF适配器模式主要技术特性 (3)

1.1.2适配器模式的程序结构 (7)

1.2适配器模式的应用示例 (13)

1.2.1类适配器的应用示例 (13)

1.2.2对象适配器的应用示例 (22)

1.2.3应用适配器模式实现组合转换器的应用实例 (26)

1.1GoF适配器模式及应用

1.1.1GoF适配器模式主要技术特性

1、为什么要提供变压器(适配器,Adapter)模式

(1)在进行系统集成时经常遇到的问题是接口不一致——接口不匹配

很多能满足应用功能的软件系统中的功能模块,由于接口不同,而导致无法使用。比如,常见的媒体播放器软件有微软的Media Player和另一个媒体播放器软件RealNetworks公司的RealPlay。但由于它们的接口完全不同和主持不同的音频和视频格式——前者支持WMF格式的音频和视频,而后者支持RM格式的音频和视频。

(2)如何解决接口不匹配的问题

如果开发人员希望自己的应用系统中能使用相同的方式来支持这两种播放器,就需要提供一个相互“适配”的转换接口——也就是可以应用适配器模式解决这个问题。该适配器类可以将WMF格式的音频和视频转换为RM格式的音频和视频,从而可以重用RealPlay的媒体播放器软件;当然,该适配器类也可以将RM格式的音频和视频转换为WMF格式的音频和视频,从而可以重用Media Player的媒体播放器软件。

(3)什么是适配器模式

GOF在他们的设计模式一书中对适配器模式的描述如下:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

其实上面的定义核心思想:在新接口和老接口之间进行适配。

2、适配器模式的主要作用

(1)匹配不同接口的程序类

适配器模式可以使得原本由于接口不兼容而不能一起工作的类可以一起工作,通过提供适配器类可以实现将一种“接口”转换为另一种“接口”,以满足目标“接口”的应用要求和重用原有的功能实现的程序代码。

由于适配器提供了一种“转换”,使得可以复用一个接口不再符合目前应用需求的已存在的功能类,也可以使一个程序类在发生不可预见的变化时,仅仅影响适配器程序类本身而不影响使用适配器程序类的不同的客户端程序类——将分散的或者发散的可变性集中在某处,有利于程序代码的维护修改。(2)重用接口不匹配的现有程序类

实现将两个或者多个没有关系(或者不兼容)的类组合在一起使用,并向客户端提供一个新的统一的功能服务接口,从而达到重用接口不匹配的现有程序类的目标。

(3)重用接口不匹配的第三方的组件

在应用开发中,经常需要重用第三方的组件,但在应用中却发现该第三方组件的接口定义和自己应用中所需要的接口定义存在差别,但又不希望修改自己的功能接口和有必要使用第三方组件接口的功能方法。

3、如何实现将两个没有关系(或者不兼容)的程序类组合在一起使用

(1)第一种解决方案是修改各自类的接口

当然,修改各自类的接口在许多应用环境下可能无法实现——比如,如果没有相关的源代码或者不愿意为了一个应用而修改各自的接口。

(2)第二种解决方案则是使用适配器模式

在这两种接口之间创建一个混合接口,该混合接口也就是适配器模式中的适配器角色,从而转换和匹配不同类型的接口。

4、应用适配器模式的主要目的是达到能够适配两个不同形式的应用目标

适配器模式在具体实现时,可以达到适配两个不同形式的应用目标:转换器和组合器。

(1)转换器

适配器模式把一个类的接口变换成客户端所期待的另一种接口,此时的适配器类其实是一种转换器的角色。

(2)组合器

适配器模式使原本无法在一起工作的两个类能够在一起工作,此时的适配器类其实也就是一种组合转换器的角色。

5、适配器模式在GOF中属于结构型模式

(1)适配器模式很象生活中的变压器

变压器可以将一种电压变换成另一种电压——比如,把美国的电器拿到中国大陆使用时,就面临着工作电压不同的问题。因为美国的生活用电压是110伏,而中国的电压是220伏。如果要在中国大陆使用在美国使用的电器设备,就必须要有一个能把220伏电压转换成110伏电压的变压器。

生活中的手机电源充电器其实也是一个适配器的应用示例。

(2)J2SDK和J2EESDK API中都提供有许多的适配器类

在J2SE中的Swing GUI组件的事件编程中经常使用事件适配器,在Java SDK中提供有很多适配器类(其实在https://www.doczj.com/doc/089327608.html,中也提供有许多的适配器类,比如https://www.doczj.com/doc/089327608.html,中的DataAdapter,它就是用作DataSet

和数据源之间的适配器)。如java.awt.event程序包中包含有如下的适配器类:ComponentAdapter、ContainerAdapter、FocusAdapter、HierarchyBoundsAdapter、KeyAdapter、MouseAdapter、MouseMotionAdapter和WindowAdapter。

在J2EE Web组件中的Servlet类其实也应用了适配器模式——当然,它实质为缺省适配器模式。主要的应用目的是简化对Servlet接口的实现。因为正常的Servlet类需要实现Servlet接口,也就是要采用下面的类定义:

public class MyServlet implements Servlet{

}

此时,在Servlet程序类中必须要重写Servlet接口中的所有方法,但在应用中可能并不需要Servlet 接口的所有方法而导致应用的复杂性——接口对接口的实现类具有强制性的要求。为此,J2EE中提供有HttpServlet类,它实现了Servlet接口——该HttpServlet类其实就是适配器模式中的适配器类。

public class HttpServlet implements Servlet{

}

public class MyServlet extends HttpServlet{

}

下面通过一个具体的应用示例说明适配器模式能够简化对接口的实现。

6、利用适配器模式能够简化对接口的实现

(1)没有采用适配器模式时的代码示例

Java面向对象中的接口和接口的实现之间的基本要求,实现类必须要实现接口中的所有成员方法,“即使不用也得实现”。下面为一个接口SomeOneInterface的定义,其中定义有三个成员方法:interface SomeOneInterface{

public void firstMethod();

public void secondMethod();

public void thirdMethod();

}

而下面的SomeOneImple为接口SomeOneInterface的实现类,但根据应用的需要,该实现其实只需要应用thirdMethod方法;而其它的两个方法firstMethod和secondMethod并不需要,但也必须要进行实现——这就使开发者非常繁琐,不需要的功能方法也需要进行重写。

public class SomeOneImple implements SomeOneInterface{

public void firstMethod(){

}

public void secondMethod(){

}

public void thirdMethod(){

/**

具体的功能实现的代码,在此省略

*/

}

public static void main(String[]args){

SomeOneInterface someOneObject=new SomeOneImple();

someOneObject.thirdMethod();

}

}

(2)采用适配器模式时的代码示例

提供一个适配器类,该适配器类实现接口SomeOneInterface中的各个方法,但在该实现类中并不对接口进行实质性的功能实现——而是在其中以空方法实现原接口中的三个方法(该类为缺省适配器模式中的适配器类),如下为代码示例。

public abstract class SomeOneDefaultAdapter implements SomeOneInterface{

public void firstMethod(){

}

public void secondMethod(){

}

public void thirdMethod(){

}

}

注意:上面的SomeOneDefaultAdapter类可以设计为抽象类,也可以不设计为抽象类。如果不希望创建SomeOneDefaultAdapter类的对象实例,则应该要将SomeOneDefaultAdapter类设计为抽象类。

此时的SomeOneImple实现类只需要继承适配器类SomeOneDefaultAdapter,而在子类中可以根据应用的需要只重写所需要的目标方法thirdMethod。

public class SomeOneImple extends SomeOneImpleAdapter{

public void thirdMethod(){

/**

具体的功能实现的代码,在此省略

*/

}

public static void main(String[]args){

SomeOneInterface someOneObject=new SomeOneImple();

someOneObject.thirdMethod();

}

}

因此,通过上面的代码示例可以了解到缺省适配器模式中的适配器类的主要作用是简化对原始的API的应用和提供更灵活的使用方式。当然,GOF的适配器模式的更大的作用并不仅仅局限于此类功能。

1.1.2适配器模式的程序结构

1、适配器模式的两种实现形式

(1)类适配器

只为某个特定的功能类进行转换和匹配的“适配”功能,不适合于对多个不同的功能类的“适配”功能。

(2)对象适配器

在Java语言(当然,也包括C#语言)中由于不支持多重继承关系,因此如果需要转换和匹配多个不同的源接口时,类适配器将不再适合应用的需要(因为采用继承关系),此时可以应用对象适配器(采用对象组合关系)。

因此,对象适配器可以应用于对多个不同的功能类的“适配”功能,可以弥补类适配器在不支持多重继承的编程语言(如Java、C#)的实现不足。

(3)缺省适配器模式

缺省适配器模式其实是一种特殊的适配器模式,其中的适配器是由一个接口的实现类承担;而在在实现类中只以空方法(方法体内没有具体的功能实现代码)的形式实现目标接口中所规定的所有方法——为接口提供缺省的实现,而具体的应用子类都继承于此抽象类。

前文介绍的J2EE Web组件技术中的javax.servlet.http.HttpServlet类其实就是缺省适配器模式中的适配器类。HttpServlet类在应用中并不需要被对象实例化,而只充当适配器的角色,它主要的作用也就为

其子类提供访问的共同接口,但其子类又可以将精力只集中在其感兴趣的方法。

2、类适配器的程序结构及应用场合

(1)程序结构实现的要求

类适配器采用继承方式对一个类继承,同时又实现一个接口的方式来与目标接口进行匹配。类适配器从功能上基本上与前面的转换适配器相同。

(2)客户所期望的目标接口中的方法比被适配的组件类中的方法还要多

下面的示例图为客户所期望的目标接口中的方法比原来的被适配的组件类还要多,其结构示图如下。

(3)客户所期望的目标接口中的方法比被适配的组件类中的方法还要少

而下面的示图为客户所期望的目标接口中的方法只是原来的被适配的组件类中的一部分方法:

(4)类适配器的应用场合

由于适配器类不仅继承了被适配的某个程序类,同时又实现了需要匹配转换的目标接口。因此,在适配器程序类中可以访问被适配的某个程序类和目标接口,从而承担起“转换”的功能。

但这种方式当所应用的语言不支持多重继承的时候(比如Java语言)而又需要适配多个不同的被适配的程序类时,则无法应用该方法。这时可以使用下面将要介绍的对象适配器。

3、类适配器和对象适配器两种实现方式中所涉及的对象角色

根据适配器所承担的转换和匹配功能,很容易了解到适配器模式的程序结构中应该有三个主要的成员对象角色——“源”、“目”和连接源目的“适配器”。

(1)目标(Target)接口

目标接口也就是所期待最终要得到的接口——客户端能够接受的接口规范。当然,目标接口可以是具体的程序类或是抽象类、接口等形式。

(2)源(Source)接口

现有需要适配的接口(Adaptee),该接口由于不再满足应用的需要,因此为了能够对它进行重用,有必要对它进行改造——但不是直接修改该接口而是通过新增适配器类最终实现转换和匹配。源接口可以是具体的程序类或是抽象类、接口等形式。

(3)适配器(Adapter)

适配器类是适配器模式的核心功能类,它能够把不再满足应用要求的源接口转换成满足目标接口要求的新的接口。显然,适配器类必须是实例类而不能是抽象类或者接口的程序形式。根据应用的不同需要和程序实现的方式不同,可以将适配器设计为类适配器和对象适配器。

4、将适配器类作为转换器角色的适配器模式的编程示例

(1)被适配的源接口

下面的代码示例代表需要适配的源接口或者称为Adaptee(被适配者),其中提供的方法someMethodToReuseable代表需要重用的方法。

public class SomeOneSource{

public void someMethodToReuseable(){

}

}

(2)期待得到的目标接口

下面的代码示例代表所期待得到的目标接口,其中的someMethodToReuseable方法是源接口中已经提供的,但还新增加有其它的方法(如otherNewMethod)——这些新增加的其它方法是源接口中没有提供的。

public interface SomeOneTarget{

void someMethodToReuseable();

void otherNewMethod();

}

(3)适配器程序类

下面的适配器程序类示例采用对目标接口(本示例为SomeOneTarget接口)进行适配实现。当然,也可以对源接口所提供的类加以继承,从而最终达到适配源接口的应用目标。

SomeOneAdapter适配器类在程序的结构实现方面,一方面实现SomeOneTarget接口,成为其实现类(这样就可以在客户端被调用),同时组合源类的对象实例以得到其具体的业务逻辑处理方法。public class SomeOneAdapter implements SomeOneTarget{

private SomeOneSource sourceObject;

/**

在对象适配器中,一般都把“源”作为构造方法的参数而传入到对象适配器类中

*/

public SomeOneAdapter(SomeOneSource sourceObject){

super();

this.sourceObject=sourceObject;

}

public void someMethodToReuseable(){

/**

重用原始接口中的功能类中的方法——通过委派的对象以得到源类中的业务逻辑处理方法

*/

sourceObject.someMethodToReuseable();

}

public void otherNewMethod(){

/**

实现目标接口中新增加的功能方法,并给出具体的代码实现

*/

}

}

在应用适配器模式时,一定要理解和关注代码重用的重要性。因为提供适配器类的最主要的目的是重用原有的功能实现,否则重新提供接口的功能实现。因此,在应用中也必须要评估是否有必要重用原有的功能实现而决定是否有必要采用适配器模式。

据此,可以了解到适配器模式一般是应用在对原有的系统功能实现的升级和维护扩展中,或者在系统的初始功能实现中需要整合第三方的应用组件由于不匹配现有的应用要求。

(4)测试程序类

public class TestSomeOneAdapter{

public static void main(String[]args){

SomeOneSource someOneSourceInstance=new SomeOneSource();

/**

客户端程序只能接收SomeOneTarget接口的实现类的对象实例

*/

SomeOneTarget oneAdapterInstance=new SomeOneAdapter(someOneSourceInstance);

/**

通过适配器程序类为客户端统一提供相关的功能服务

*/

oneAdapterInstance.someMethodToReuseable();

oneAdapterInstance.otherNewMethod();

}

}

当然,在实际的项目开发中,可以应用工厂模式或者IOC依赖注入、Java中的反射等技术进一步分离客户端程序类和SomeOneSource、SomeOneAdapter等程序类的耦合关系。

(5)为什么非要应用适配器类?有此必要吗?

为什么在本示例中要应用一个SomeOneAdapter类进行转换和匹配,而不直接修改SomeOneSource 接口和相关的实现类?之所以要应用适配器类,主要有如下的三个主要的原因:

1)原因之一是根据面向对象编程中的OCP(开-闭)原则,在对系统的代码进行维护升级时,应该尽可能不要直接修改原有的功能实现代码;

2)原因之二是所匹配的新的功能是暂时性而非永久的修改或者扩展,因此最好不要破坏原有的程序类的结构及关系;

3)原因之三,在许多实际的应用项目开发中,可能无法获得相关的源程序或者由于版权等问题,而不能修改原程序代码或者如果要修改代码,将要修改很多相关的程序代码。

5、将适配器类作为组合器的角色的适配器模式的编程示例

(1)目前已经提供的功能实现类

假设在应用开发中目前已经有两种不同的功能实现类SomeOneClass和SomeTwoClass,它们的类定义的代码示例如下。

public class SomeOneClass{

public void someOneMethod(){

System.out.println("someOneMethod方法已经执行");

}

}

public class SomeTwoClass{

public void someTwoMethod(){

System.out.println("someTwoMethod方法已经执行");

}

}

(2)作为组合转换器的适配器类的代码示例

现在根据应用的需求,需要提供一个新的功能,该功能包含有someOneMethod和someTwoMethod 的复合要求。此时,可以使用作为组合转换器的适配器类实现这个应用要求。

public class CombineAdapter extends SomeOneClass{

private SomeTwoClass oneSomeTwoClassInstance;

public CombineAdapter(){

this.oneSomeTwoClassInstance=SomeTwoClassFactory.getSomeTwoClassInstance();

}

public void someTwoMethod(){

/**

其实在适配器角色中不仅仅可以完成接口转换的功能,而且还可以对其进行改进和功能扩展。只需要在此增加相关的功能实现代码。

*/

oneSomeTwoClassInstance.someTwoMethod();

}

}

组合转换器的适配器类的程序结构定义要求:CombineAdapter(组合转换器的适配器类)首先继承SomeOneClass(目标),然后内聚一个SomeTwoClass(被适配者)类的对象,并且重载SomeTwoClass 类中的someTwoMethod()方法。为了分离CombineAdapter类和SomeTwoClass类之间的耦合关系,而不直接在程序代码中创建SomeTwoClass类的对象实例,而是统一由SomeTwoClassFactory工厂类创建。下面为SomeTwoClassFactory工厂类的代码示例:

public class SomeTwoClassFactory{

public static SomeTwoClass getSomeTwoClassInstance(){

SomeTwoClass oneSomeTwoClassInstance=null;

oneSomeTwoClassInstance=new SomeTwoClass();

return oneSomeTwoClassInstance;

}

}

在上面代码中,SomeTwoClass程序类此时属于被适配者的程序类,而CombineAdapter是组合转换器的适配器类。

(3)客户端的代码示例

public class CombineAdapterClient{

public static void main(String args[]){

CombineAdapterClient oneCombineAdapterClient=new CombineAdapterClient();

oneCombineAdapterClient.someOneMethod();

oneCombineAdapterClient.someTwoMethod();

}

}

1.2适配器模式的应用示例

1.2.1类适配器的应用示例

1、类适配器应用示例一

(1)本示例的功能需求描述

比如在某个BBS论坛的应用系统中定义有一个前台用户信息管理的接口UserInfoManageInterface,并在其中声明了三个业务功能方法、也有该接口的具体实现类UserInfoManageImple。但现在还需要设计一个后台管理的业务功能,但对于在后台管理功能中并不需要UserInfoManageInterface接口中的全部业务方法,同时还需要新的业务功能方法并形成后台业务管理功能的AdminInfoManageInterface接口。(2)体现本示例功能要求的UML类图

具体的功能要求请见下面的类图所示的各个方法定义的要求,其中UserInfoManageInterface为原始的接口(在适配器模式中称为被适配的组件接口),而AdminInfoManageInterface接口为新的目标接口(在适配器模式中称为所期望新的要求接口)。

(3)被适配的组件原始接口UserInfoManageInterface的定义

被适配的组件接口UserInfoManageInterface具体的定义请见下面的代码示例。如果要使用这个接口,根据Java语言中的接口实现的具体要求,该接口的实现类UserInfoManageImple就必须要实现UserInfoManageInterface接口中的这三个方法,缺一不可。

UserInfoManageImple实现类的代码请见下面的代码示例。为了节省本书的篇幅,省略了无关的代码语句。

package com.px1987.webbbs.model;

public interface UserInfoManageInterface{

public boolean doUserLogin(UserInfoVO oneUserInfoVO);

public boolean doUserRegister(UserInfoVO oneUserInfoVO);

public boolean doUpdateOneUserInfo(UserInfoVO oneUserInfoVO);

}

(4)原始接口UserInfoManageInterface的实现类UserInfoManageImple定义

但有时候,实现类只需要应用接口中的部分方法或者客户所需要的方法不完全是该接口中的方法、还需要其它的业务方法,这就使得实现类的开发者非常繁琐,不需要的功能方法在实现类中也必须要进行重写、同时需要的功能方法又没有定义出!请见下面的UserInfoManageImple的代码示例。

package com.px1987.webbbs.model;

public class UserInfoManageImple implements UserInfoManageInterface{

public UserInfoManageImple(){

}

public boolean doUserLogin(UserInfoVO oneUserInfoVO){

/**

。。。具体的功能实现代码,在此加以省略

*/

return true;

}

public boolean doUserRegister(UserInfoVO oneUserInfoVO){

/**

。。。具体的功能实现代码,在此加以省略

*/

return true;

}

public boolean doUpdateOneUserInfo(UserInfoVO oneUserInfoVO){

/**

。。。具体的功能实现代码,在此加以省略

*/

return true;

}

}

(5)新的目标功能要求的接口定义

后台业务管理功能的AdminInfoManageInterface接口的定义要求请见下面的代码示例,对比两个接口的定义,发现两者之间有相同的方法定义但又有差别。如何能够将UserInfoManageInterface接口转换为AdminInfoManageInterface接口,以使得能够重用UserInfoManageInterface接口的实现类UserInfoManageImple中的doUserLogin和doUpdateOneUserInfo方法的实现,因为这两个方法也同样适用于后台管理功能实现!

package com.px1987.webbbs.model;

public interface AdminInfoManageInterface{

public boolean doUserLogin(UserInfoVO oneUserInfoVO);

public boolean doUpdateOneUserInfo(UserInfoVO oneUserInfoVO);

public boolean doDeleteOneUserInfo(UserInfoVO oneUserInfoVO);

public ArrayList doGetAllRegisterUserInfo();

}

(6)利用适配器组件类来匹配两个不同的接口但又不希望直接修改原始的接口

此时开发者可以通过添加一个适配器组件类UserInfoManageAdapter,该适配器组件类

UserInfoManageAdapter一方面继承于UserInfoManageImple类、同时又实现AdminInfoManageInterface 接口。具体请见下面的UserInfoManageAdapter适配器组件类的代码示例,对于doUserLogin和doUpdateOneUserInfo业务功能方法则直接调用基类UserInfoManageImple类中的对应的方法以重用原来的功能,而对于新的方法doDeleteOneUserInfo和doGetAllRegisterUserInfo,则给出具体的功能实现。

为了节省本书的篇幅,省略了无关的代码语句。下面为具体实现的代码示例。

package com.px1987.webbbs.model;

import java.util.*;

public class UserInfoManageAdapter extends UserInfoManageImple

implements AdminInfoManageInterface{

public UserInfoManageAdapter(){

}

public boolean doUserLogin(UserInfoVO oneUserInfoVO){

return super.doUserLogin(oneUserInfoVO);

}

public boolean doUpdateOneUserInfo(UserInfoVO oneUserInfoVO){

return super.doUpdateOneUserInfo(oneUserInfoVO);

}

public boolean doDeleteOneUserInfo(UserInfoVO oneUserInfoVO){

/**

。。。具体的功能实现代码,在此加以省略

*/

return true;

}

public ArrayList doGetAllRegisterUserInfo(){

/**

。。。具体的功能实现代码,在此加以省略

*/

return null;

}

}

因此将原来的UserInfoManageInterface接口经过适当的“适配”后就能够满足新的客户的需要,同时也能够简化客户端的编程使用方式——请见下面的后台用户信息管理模块中的控制层AdminInfoAction类的代码示例。

下面的AdminInfoAction类为基于Struts框架的DispatchAction技术的实现类,在其中只给出了一个实现管理员登陆功能的goUserLogin方法的部分实现的代码示例。为了节省本书的篇幅,省略了无关的代码语句。

package com.px1987.webbbs.action;

import com.px1987.webbbs.model.*;

public class AdminInfoAction extends DispatchAction{

public ActionForward goUserLogin(ActionMapping mapping,ActionForm form,

HttpServletRequest request,HttpServletResponse response){ UserInfoVO oneUserInfoVO=new UserInfoVO();

/**

。。。获得用户表单所提交的表单参数,并设置到oneUserInfoVO对象中对应的属性等方面的功能实现代码在此加以省略

*/

AdminInfoManageInterface userInfoManageAdapter=

new UserInfoManageAdapter();

userInfoManageAdapter.doUserLogin(UserInfoVO oneUserInfoVO);

/**

。。。其它功能代码,在此加以省略

*/

}

/**

。。。其它功能方法的实现代码,在此加以省略

*/

}

2、类适配器应用示例二

(1)问题的应用背景说明

现在有这样一个场景:在某项目中需要使用一个第三方的日志记录工具,该日志记录工具支持控制

台、数据库和文本文件等记录输出方式,但它所提供给的API接口是outPutLog()方法(该方法也就是适配器模式中的目标接口)。

(2)现需要改变为应用另一个日志工具

当软件系统开发进行到一半时,处于某种原因不能继续使用该日志记录工具而需要采用另外一个日志记录工具,它同样也支持控制台、数据库和文本文件等记录输出方式,只不过它提供的API接口是writeLog()方法(该方法也就是适配器模式中的源接口)。

(3)应用类适配器适配这样的接口

当然,可以采用直接修改现有的日志记录工具的API接口,但是由于版权等原因不能够修改它的源代码,此时Adapter模式便可以派上用场并转换和匹配源接口和目标接口。

(4)实现的代码示例

下面的ILogTarget接口为适配器模式中的目标接口,其中定义有outPutLog方法为原始的日志功能实现的方法;而Console_LogTarget为ILogTarget接口的具体实现类,将日志信息在控制台中输出。package com.px1987.adapterpattern;

public interface ILogTarget{

public boolean outPutLog(String logInfo);

}

package com.px1987.adapterpattern;

public class Console_LogTarget implements ILogTarget{

public Console_LogTarget(){

}

@Override

public boolean outPutLog(String logInfo){

/**

本示例没有真正第实现日志信息的输出,而只是简单第返回操作成功的标志

*/

return false;

}

}

下面的TextFile_LogTarget同样也为ILogTarget接口的具体实现类,但将日志信息存储在文件中。package com.px1987.adapterpattern;

public class TextFile_LogTarget implements ILogTarget{

public TextFile_LogTarget(){

}

@Override

public boolean outPutLog(String logInfo){

/**

本示例没有真正第实现日志信息的输出,而只是简单第返回操作成功的标志

*/

return false;

}

}

下面的ILogSource接口为适配器模式中的源接口,其中定义有writeLog方法为需要转换的日志功能实现的方法——也就是将writeLog方法转换以满足outPutLog的应用需要;而Console_LogSource为ILogSource接口的具体实现类,将日志信息在控制台中输出。

package com.px1987.adapterpattern;

public interface ILogSource{

public boolean writeLog(String logInfo);

}

package com.px1987.adapterpattern;

public class Console_LogSource implements ILogSource{

public Console_LogSource(){

}

@Override

public boolean writeLog(String logInfo){

/**

本示例没有真正第实现日志信息的输出,而只是简单第返回操作成功的标志

*/

return false;

}

}

下面的TextFile_LogSource同样也为ILogSource接口的具体实现类,但将日志信息存储在文件中。package com.px1987.adapterpattern;

public class TextFile_LogSource implements ILogSource{

public TextFile_LogSource(){

}

@Override

public boolean writeLog(String logInfo){

/**

本示例没有真正第实现日志信息的输出,而只是简单第返回操作成功的标志

*/

return false;

}

}

下面的ConsoleLogAdapte为控制台日志信息转换的适配器类,该类一方面继承于Console_LogSource 类,同时又实现ILogTarget接口。

package com.px1987.adapterpattern;

public class ConsoleLogAdapter extends Console_LogSource implements ILogTarget{ public ConsoleLogAdapter(){

}

@Override

public boolean outPutLog(String logInfo){

/**

当客户端调用原始的接口方法outPutLog时,转换为调用源接口中的日志信息的具体功能实现方法,从而对源接口中的日志信息的功能实现代码进行重用。最终也就实现了转换的功能。

*/

return this.writeLog(logInfo);

}

}

下面的TextFileLogAdapter为文件日志信息转换的适配器类,该类一方面继承于TextFile_LogSource 类,同时又实现ILogTarget接口。

软件设计师23种设计模式总结

创建型结构型行为型 类Factory Method Adapter In terpreter Template Method 对象 Abstract Factory Builder Prototype Si ngleto n Apapter(对象) Bridge Composite Decorator Fa?ade Flyweight Proxy Chain of Resp on sibility Comma nd Iterator Mediator Meme nto Observer State Strategy Visitor (抽象工厂) 提供一个创建一系列相关或互相依赖对象的接口,而无须制定它们具体的类。 图10-25抽象工厂模式结构图 Abstract Factory 抽象工厂 class Program { static void Main(string[] args) { AbstractFactory factory1 = new Con creteFactory1(); Clie nt c1 = new Clie nt(factory1); c1.Ru n(); AbstractFactory factory2 = new Con creteFactory2(); Clie nt c2 = new Clie nt(factory2); c2.Ru n(); Co nsole.Read(); abstract class AbstractFactory { public abstract AbstractProductA CreateProductA(); public abstract AbstractProductB

通过代码示例学习GOF 设计模式(第13章适配器模式)

前言 软件开发工作从本质上属于创造性的工作,它是一种将“软件产品”从无到有生的创建过程。行业内流行的“站在巨人的肩膀上”、“不要重复地发明轮子”、“不要不断地重复自己”等“名言警句”其实都是对“软件复用”思想的具体体现。 面向对象程序设计方法提供了类级别的重用;而基于“组件化”的复用方式,已使软件系统产品在质量保证、开发效率等方面得到了更大的提高;面向框架级的系统集成开发(如J2EE中的SSH、https://www.doczj.com/doc/089327608.html,、PHP的LAMP等),不仅可以实现组件级别的重用,而且在系统的总体架构、软件设计思想等方面都可以得到重用。因此“面向对象”、“组件化”、“基于XML的数据结构描述”、“面向框架”等设计思想和实现技术,更使得软件系统的“复用”达到了一个更深的层次,随之而来的各种企业级“中间件组件”、AOP、SOA等技术的出现,也使得开发者的主要精力可以越来越多地关注于应用系统的业务逻辑和业务数据,而非系统“底层”的具体实现技术和各个不同技术平台之间、各个数据库系统之间的差异。 作者接触很多高校计算机软件专业类的教师和学生,深感目前的计算机软件开发类专业的程序设计类各个课程在教学方面的欠缺,不仅编码不规范(胡写代码和混乱命名)、技术深度不足(学C语言不学习指针、学Java不学习集合、反射和范型),而且程序代码还存在许多不可靠、性能低下、扩展性差等方面的问题;国内许多“小作坊”型的软件公司人员不断地生产出大量的“垃圾代码”,从而使得这些软件公司的项目都是“一次性买卖”,客户方受骗后再也没有第二次的项目开发。 作者根据自身多年的软件开发实践和经验总结,结合多年的IT职业培训的教学和高校软件学院一线的教学工作体验,在本系列文档中通过具体的程序代码示例为读者介绍GOF 设计模式及相关的应用技术。主要的目的是希望能够以成功的经验或者失败的教训为读者减少软件开发失败的风险,同时也为高校师生总结出如何能够编程开发出一个“易读的”、“易维护的”、“易扩展”、“高性能”和“可重用”的系统程序。 本文档主要涉及GoF适配器模式及应用、适配器模式主要技术特性和程序结构,适配器模式的应用示例、类适配器的应用示例、对象适配器的应用示例和如何应用适配器模式实现组合转换器的应用实例等方面的内容。 杨教授大学堂精心创作有系列化的优秀程序员职业提升必读技术资料,这些资料将系统地从软件设计和开发实现的“设计思想”、“管理策略”、“技术实现”和“经验方法”等方面与读者进行充分的交流,涉及作者对软件开发设计思想和原则、课程设计、项目实训、软件实现技术等方面的学习心得体会和应用技巧、经验总结。

23种设计模式趣味讲解

23种设计模式趣味讲解 对设计模式很有意思的诠释,呵呵,原作者不详。 创立型模式 1、FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,固然口味有所不同,但不管你带MM往麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了。麦当劳和肯德基就是生产鸡翅的Factory 工厂模式:客户类和工厂类离开。花费者任何时候需要某种产品,只需向工厂恳求即可。花费者无须修正就可以接纳新产品。毛病是当产品修正时,工厂类也要做相应的修正。如:如何创立及如何向客户端供给。 2、BUILDER—MM最爱听的就是“我爱你”这句话了,见到不同处所的MM,要能够用她们的方言跟她说这句话哦,我有一个多种语言翻译机,上面每种语言都有一个按键,见到MM 我只要按对应的键,它就能够用相应的语言说出“我爱你”这句话了,国外的MM也可以轻松搞掂,这就是我的“我爱你”builder。(这必定比美军在伊拉克用的翻译机好卖) 建造模式:将产品的内部表象和产品的天生过程分割开来,从而使一个建造过程天生具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变更,客户不必知道产品内部组成的细节。建造模式可以强迫履行一种分步骤进行的建造过程。 3、FACTORY METHOD—请MM往麦当劳吃汉堡,不同的MM有不同的口味,要每个都记住是一件烦人的事情,我一般采用Factory Method模式,带着MM到服务员那儿,说“要一个汉堡”,具体要什么样的汉堡呢,让MM直接跟服务员说就行了。 工厂方法模式:核心工厂类不再负责所有产品的创立,而是将具体创立的工作交给子类往做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的串口,而不接触哪一个产品类应当被实例化这种细节。 4、PROTOTYPE—跟MM用QQ聊天,必定要说些深情的话语了,我搜集了好多肉麻的情话,需要时只要copy出来放到QQ里面就行了,这就是我的情话prototype了。(100块钱一份,你要不要) 原始模型模式:通过给出一个原型对象来指明所要创立的对象的类型,然后用复制这个原型对象的方法创立出更多同类型的对象。原始模型模式容许动态的增加或减少产品类,产品类不需要非得有任何事先断定的等级结构,原始模型模式实用于任何的等级结构。毛病是每一个类都必须配备一个克隆方法。 5、SINGLETON—俺有6个美丽的老婆,她们的老公都是我,我就是我们家里的老公Sigleton,

软件设计模式试题集 含答案

设计模式试题 一.选择 1. 设计模式具有的优点()。 A.适应需求变化 B.程序易于理解 C.减少开发过程中的代码开发工作量 D.简化软件系统的设计 2. 设计模式一般用来解决什么样的问题( )。 A.同一问题的不同表相 B 不同问题的同一表相 C.不同问题的不同表相 D.以上都不是 3. 设计模式的两大主题是( )。 A.系统的维护与开发 B.对象组合与类的继承 C.系统架构与系统开发 D.系统复用与系统扩展 4. 以下哪些问题通过应用设计模式不能够解决。() A)指定对象的接口B)针对接口编程 C)确定软件的功能都正确实现D)设计应支持变化 二.填空 1. 模式的基本要素包括名称、意图、问题、解决方案、参与者和协作者、(效果)、实现、GoF 参考。 2. 设计模式基本原则包括:开闭原则,(从场景进行设计的原则),包容变化原则。 3. 设计模式是一个(抽象)的方案,它可以解决一类问题。 4. 1. 在设计模式群体中,效果是指(原因和结果)。三. 判断 1. 适配器模式属于创建型模式。错 2. 在设计模式中,“效果”只是指“原因和结果”。对 3. 设计模式使代码编制不能真正工程化。错 4. 设计模式的两大主题是系统复用与系统扩展。对四. 名词解释 1. 设计模式 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 2. 模板 模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 3. 模式 就是解决某一类问题的方法论。把解决某类问题的方法总结归纳到理论高度,那就是模式。 4. 内聚度 模块内部各成分彼此结合的紧密程度。五.简答 题 1. 什么是设计模式?设计模式的目标是什么?设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验的总结。使用设计模式是为了可 重用代码、让代码更容易被他人理解、保证代码可靠性。 2. 设计模式的基本要素有哪些? 名称,意图,问题,解决方案,参与者和协作者,效果,实现,GOF 参考。 3. 设计模式中一般都遵循的原则有什么? 开-闭原则,根据场景进行设计原则,优先组合原则,包容变化原则。 4. 四人团针对“创建优秀面向对象设计”建议了哪些策略? 针对接口编程,优先使用对象组合而不是类继承,找到并封装变化点。 第6 章 facade(外观)模式 一.选择 1. 外观模式的作用是()。A.当不能采用生成子类的方法进行扩充时,动态地给一个对象添加一些 额外的功能。B.为了系统中的一组功能调用提供一个一致的接口,这个接口使得这一子系统更 加容易使用。

Gof的23种设计模式

Gof的23种设计模式 从2005年初听说设计模式,到现在虽然已经8年多了,但GoF的23种模式依然盛行,当然GoF提出这些模式的 年代更加久远(1995年)。在工作的过程中,陆陆续续接触了GoF的大部分模式,我记得在2008年的时候就想总结一下设计模式(最近想做的两件事情),最后因为各种原 因也没有完成。最近这段时间正好是职业空档期,没什么事儿做,就把之前看过的设计模式翻出来整理了一下,于是就有了上面几篇文章。整理设计模式的过程,也是一个深刻理解面向对象设计的过程。通过对各个模式的回顾,让我更能够明白前辈们关于面向对象设计提出的各种“最佳实践”,特别是S.O.L.I.D,我觉得在这里再说一次,也不算矫情。S:单一职责原则(Single Responsibility Principle, SRP),一个类只能有一个原因使其发生改变,即一个类只承担一个职责。 O:开放-封闭原则(Open-Close Principle, OCP),这里指我们的设计应该针对扩展开放,针对修改关闭,即尽量以扩展的方式来维护系统。 L:里氏替换原则(Liskov Subsititution Principle, LSP),它表示我们可以在代码中使用任意子类来替代父类并且程 序不受影响,这样可以保证我们使用“继承”并没有破坏父类。

I:接口隔离原则(Interface Segregation Principle, ISP),客户端不应该依赖于它不需要的接口,两个类之间的依赖应该建立在最小接口的基础上。这条原则的目的是为了让那些使用相同接口的类只需要实现特定必要的一组方法,而不是大量没用的方法。 D:依赖倒置原则(Dependence Inversion Principle, DIP),高层模块不应该依赖于低层模块,两者应该都依赖于抽象;抽象不依赖于细节,而细节应该依赖于抽象。这里主要是提倡“面向接口”编程,而非“面向实现”编程。设计模式,从本质上讲,是针对过去某种经验的总结。每种设计模式,都是为了在特定条件下去解决特定问题,离开这些前提去讨论设计模式,是没有意义的。下面,我们快速回顾GoF的23种模式。工厂方法 意图:定义一个用户创建对象的接口,让子类去决定具体使用哪个类。 适用场合:1)类不知道它所要创建的对象的类信息;2)类希望由它的子类来创建对象。抽象工厂 意图:提供一个创建一系列相关或者相互依赖的对象的接口,而无须指定它的具体实现类。 适用场合:1)系统不依赖于产品是如何实现的细节;2)系统的产品族大于1,而在运行时刻只需要某一种产品族;3)属于同一个产品族的产品,必须绑在一起使用;4)所有的

设计模式 结构型模式(包含7种)

设计模式——结构型模式(包含7种) 结构型设计模式是从程序的结构上解决模块之间的耦合问题。包括以下七种模式: 1.Adapte适配器模式:Adapter模式通过类的继承或者对象的组合侧重于转换已有的接口,类适配器采用“多继承”的实现方式,带来了不良的高耦合,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神。 例如:笔记本电源适配器,可以将220v转化为适合笔记本使用的电压。 2.Bridge桥接模式:将抽象部分与实现部分分离,使它们都可以独立的变化。减少因变化带来的代码的修改量。 例如:经典例子,电灯开关,开关的目的是将设备打开或关闭,产生的效果不同。 https://www.doczj.com/doc/089327608.html,posite组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite模式使得客户对单个对象和组合对象的使用具有一致性。从而解决了解决客户程序与复杂对象容器的解耦,即:通过继承统一的接口,我们可以将容器对象及其子对象看成同一类对象使用,以减少对象使用中的复杂度。 例如:让用户一致地使用单个对象和组合对象,1+2和(1+1)+(2*3)都是合法的表达式。单个与整体都可以进行加法运算符的操作。 4.Decorator装饰模式:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。[GOF 《设计模式》]Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。 例如:一幅画,可以直接挂到墙上,也可以加上框架和镶上玻璃后,再挂到墙上。 5.Facade外观模式:为子系统中的一组接口提供一个一致的界面,简化接口。 例如:我们拨打10086,可以办理,彩铃,手机报,全时通等业务(子对象),而10086则是为子对象所使用的一致界面。 6.Flyweight享元模式:运用共享技术有效地支持大量细粒度的对象。[GOF 《设计模式》]。解决:面向对象的思想很好地解决了抽象性的问题,一般也不会出现性能上的问题。但是在某些情况下,对象的数量可能会太多,从而导致了运行时的代价。那么我们如何去避免大量细粒度的对象,同时又不影响客户程序使用面向对象的方式进行操作,享元模式的出现恰好解决了该问题。 例如:公共交换电话网(PSTN)是享元的一个例子。有一些资源例如拨号音发生器、振铃发生器和拨号接收器是必须由所有用户共享的。当一个用户拿起听筒打电话时,他不需要知道使用了多少资源。对于用户而言所有的事情就是有拨号音,拨打号码,拨通电话。

设计模式复习题

三、题目预测 填空题: 1.请从外观、组合、工厂方法、模板方法、观察者、单件、抽象工厂、命令、迭代器、代理、适配器模式 中选择 7 种填入下列的空缺中。 P610 1)工厂方法模式中,父类负责定义创建对象的公共接口,子类决定要创建的具体类是哪一个。 2)抽象工厂模式提供一系列相关或相互依赖对象的接口而无需指定它们具体的类。 3)单件模式确保某一个类仅有一个实例,并自行实例化并向整个系统提供这个实例。 4)组合模式将对象组合成树形结构以表示“部分 -整体”的层次结构。使得用户对单个对象和组合对象的使用具有一致性。 5)外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用,为子系统中的一组接口提供一个一致的界面,简化了一群类的接口。 6)观察者模式定义对象间的一种一对多的依赖关系 , 当一个对象的状态发生改变时 , 所有依赖于它的对象都得到通知并被自动更新,也就是让对象能在状态改变时被通知。 7)模板模 MVC 模型式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 8)迭代器模式在对象的集合之中游走,而不暴露集合的实现。 9)代理模式包装对象,以控制对比对象的访问。 10)适配器模式封装对象,并提供不同的接口。 2.工厂模式分为 ( 简单工厂 ),( 工厂方法 ),( 抽象工厂 ) 三种类型。 3.适配器模式,分为类的适配器和对象的适配器两种实现。其中类的适配器采用的是(继承)关系,而对 象适配器采用的是(组合聚合)关系。 4.设计模式的基本要素有(名字),(意图),(问题),(解决方案),(参与者与协作者),(实现),(一般性结构)。 5.MVC 模型的基本工作原理是基于 ( 观察者 )模式,实现是基于(命令)模式 6.面向对象的六条基本原则包括:开闭原则,里式代换原则,合成聚合原则以及(依赖倒转),(迪米特 法则)(接口隔离)。 7 .当我们想用不同的请求对客户进行参数化时,可以使用(命令)模式。

二十三种设计模式类图

二十三种设计模式类图 0 引言 谈到设计模式,绝对应该一起来说说重构。重构给我们带来了什么?除了作为对遗留代码的改进的方法,另一大意义在于,可以让我们在写程序的时候可以不需事先考虑太多的代码组织问题,当然这其中也包括了应用模式的问题。尽管大多数开发者都已经养成了写代码前先从设计开始的习惯,但是,这种程度的设计,涉及到到大局、到总体架构、到主要的模块划分我觉得就够了。换句话说,这时就能写代码了。这就得益于重构的思想了。如果没有重构的思想,有希望获得非常高质量的代码,我们就不得不在开始写代码前考虑更多其实并非非常稳定的代码组织及设计模式的应用问题,那开发效率当然就大打折扣了。在重构和设计模式的合理应用之下,我们可以相对较早的开始写代码,并在功能尽早实现的同时,不断地通过重构和模式来改善我们的代码质量。所以,下面的章节中,在谈模式的同时,我也会谈谈关于常用的这些模式的重构成本的理解。重构成本越高意味着,在遇到类似的问题情形的时候,我们更应该提前考虑应用对应的设计模式,而重构成本比较低则说明,类似的情形下,完全可以先怎么方便,怎么快怎么写,哪怕代码不是很优雅也没关系,回头再重构也很容易。 1 创建型 1.1FactoryMethod 思想:Factory Method的主要思想是使一个类的实例化延迟到其子类。 场景:典型的应用场景如:在某个系统开发的较早阶段,有某些类的实例化过程,实例化方式可能还不是很确定,或者实际实例化的对象(可能是需要对象的某个子类中的一个)不确定,或者比较容易变化。此时,如果直接将实例化过程写在某个函数中,那么一般就是if-else或select-case代码。如果,候选项的数目较少、类型基本确定,那么这样的if-else 还是可以接受的,一旦情形变得复杂、不确定性增加,更甚至包含这个构造过程的函数所

Java23种设计模式6大原则总结

设计模式概念:一套被反复使用、多数人知晓、经过分类编目的优秀代码设计经验的总结。设计模式要素:模式名称、问题、举例、末态环境、推理、其他有关模式、已知的应用。设计模式分类:创建型、结构型、行为型。 创建型模式功能:1.统所使用的具体类的信息封装起来; 2.类的实例是如何被创建和组织的。 创建型模式作用:1.封装创建逻辑,不仅仅是new一个对象那么简单。 2.封装创建逻辑变化,客户代码尽量不修改,或尽量少修改。 常见的创建型模式:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。常见的结构型模式:代理模式、装饰模式、适配器模式、组合模式、桥梁模式、外观模式、享元模式。 常见行为型模式:模板方法模式、命令模式、责任链模式、策略模式、迭代器模式、中介者模式、观察者模式、备忘录模式、访问者模式、状态模式、解释器模式。单一职责原则:一个类应该只有一个职责。 优点:降低类的复杂性;提高类的可读性;提高代码的可维护性和复用性;降低因变更引起的风险。 里氏替换原则: 优点:代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;提高代码的可重用性;提高代码的可扩展性;提高产品或项目的开放性。 缺点:1.继承是入侵式的。只要继承,就必须拥有父类所有属性和方法。 2.降低代码的灵活性。子类必须拥有父类的属性和方法,使子类收到限制。 3.增强了耦合性。当父类的常量、变量和方法修改时,必须考虑子类的修改,这种 修改可能造成大片的代码需要重构。 依赖倒置原则:高层模块不应该依赖低层模块,两者都依赖其抽象;抽象不依赖细节;细节应该依赖于抽象。 在Java中的表现:模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;接口或抽象类不依赖于是实现类; 实现类依赖于接口或抽象类。 接口隔离原则:1.一个类对另外一个类的依赖性应当是建立在最小的接口上的 2.一个接口代表一个角色,不应当将不同的角色交给一个接口。 3.不应该强迫客户使用它们的不同方法。 如图所示的电子商务系统在三个地方会使用到订单类:一个是门户,只能有查询方法;一个是外部系统,有添加订单的方法;一个是管理后台,添加、删除、修改、查询都要用到。“原子”在实践中的衡量规则: 1.一个接口只对一个子模块或者业务逻辑进行分类。 2.只保留接口中业务逻辑需要的public方法。 3.尽量修改污染了的接口,若修改的风险较大,则可采用适配器模式进行转化处理。 4.接口设计应因项目而异,因环境而异,不能照搬教条。 迪米特法则:(表述)只与你直接的朋友们通信;不要跟“陌生人”说话;每一个软件单位 对其他的单位都只有最少的了解,这些了解仅局限于那些与本单位密 切相关的软件单位。 对迪米特法则进行模式设计有两个:外观模式、中介者模式。 开闭原则:一个软件实体应当对扩展开放,对修改关闭。 重要性体现:提高复用性;提高维护性;提高灵活性;易于测试

几种常用的设计模式介绍

几种常用的设计模式介绍 1. 设计模式的起源 最早提出“设计模式”概念的是建筑设计大师亚力山大Alexander。在1970年他的《建筑的永恒之道》里描述了投计模式的发现,因为它已经存在了千百年之久,而现代才被通过大量的研究而被发现。 在《建筑的永恒之道》里这样描述:模式是一条由三个部分组成的通用规则:它表示了一个特定环境、一类问题和一个解决方案之间的关系。每一个模式描述了一个不断重复发生的问题,以及该问题解决方案的核心设计。 在他的另一本书《建筑模式语言》中提到了现在已经定义了253种模式。比如: 说明城市主要的结构:亚文化区的镶嵌、分散的工作点、城市的魅力、地方交通区 住宅团组:户型混合、公共性的程度、住宅团组、联排式住宅、丘状住宅、老人天地室内环境和室外环境、阴和阳总是一气呵成 针对住宅:夫妻的领域、儿童的领域、朝东的卧室、农家的厨房、私家的沿街露台、个人居室、起居空间的序列、多床卧室、浴室、大储藏室 针对办公室、车间和公共建筑物:灵活办公空间、共同进餐、共同小组、宾至如归、等候场所、小会议室、半私密办公室 尽管亚力山大的著作是针对建筑领域的,但他的观点实际上适用于所有的工程设计领域,其中也包括软件设计领域。“软件设计模式”,这个术语是在1990年代由Erich Gamma等人从建筑设计领域引入到计算机科学中来的。目前主要有23种。 2. 软件设计模式的分类 2.1. 创建型 创建对象时,不再由我们直接实例化对象;而是根据特定场景,由程序来确定创建对象的方式,从而保证更大的性能、更好的架构优势。创建型模式主要有简单工厂模式(并不是23种设计模式之一)、工厂方法、抽象工厂模式、单例模式、生成器模式和原型模式。 2.2. 结构型 用于帮助将多个对象组织成更大的结构。结构型模式主要有适配器模式、桥接模式、组合器模式、装饰器模式、门面模式、亨元模式和代理模式。 2.3. 行为型 用于帮助系统间各对象的通信,以及如何控制复杂系统中流程。行为型模式主要有命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板模式和访问者模式。

设计模式考试复习题

一、1. 设计模式一般用来解决什么样的问题: A.同一问题的不同表相 2. 下列属于面向对象基本原则的是: C.里氏代换 3. Open-Close原则的含义是一个软件实体:A.应当对扩展开放,对修改关闭. 4. 当我们想创建一个具体的对象而又不希望指定具体的类时,使用(A)模式。A.创建型 5. 要依赖于抽象不要依赖于具体。即针对接口编程不要针对实现编程:(D)依赖倒转原则 6. 依据设计模式思想,程序开发中应优先使用的是( A )关系实现复用。A, 委派 7. 设计模式的两大主题是( D ) D.系统复用与系统扩展 8. 单体模式中,两个基本要点(AB)和单体类自己提供单例A .构造函数私有 B.唯一实例 9. 下列模式中,属于行为模式的是( B ) B观察者 10. “不要和陌生人说话”是( D )原则的通俗表述 D.迪米特 1. 软件体系结构是指一个系统的有目的的设计和规划,这个设计规划既不描述活动,也不描述系统怎样开发,它只描述系统的组成元素及其相互的交互协作。 2.一个UML模型只描述了一个系统要做什么,它并没告诉我们系统是怎么做。 3.接口是可以在整个模型中反复使用的一组行为,是一个没有属性而只有方法的类。 4.多重性指的是,某个类有多个对象可以和另一个类的一对象关联。 5.当一个类的对象可以充当多种角色时,自身关联就可能发生。 6.在泛化关系中,子类可以替代父类。后前者出现的可以相同地方。反过来却不成立。 7.最通常的依赖关系是一个类操作的形构中用到了另一个类的定义。 8.组成是强类型的聚集,因为聚集中的每个部分体只能属于一个整体。 9.实现的符号和继承的符号有相似之处,两者的唯一差别是实现关系用虚线表示,继承关系用实线表示。 10. 设计模式中应优先使用对象组合而不是类继承。 1.适配器模式属于创建型模式结构型( F ) 2.在设计模式中,“效果”只是指“原因和结果”( T ) 3.设计模式使代码编制不能真正工程化( T ) 4.面向对象语言编程中的异常处理,可以理解为责任链模式(T ) 5.反模式就是反对在软件开发过程中使用设计模式分析:反模式用来解决问题的带有共性的不良方法(F ) 1.什么是设计模式?设计模式目标是什么? 答:设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解,保证代码可靠性。 2.设计模式中一般都遵循的原则有什么? 答:开闭原则、根据场景进行设计原则、优先组合原则、包容变化原则 3.“Gang of Four”针对“创建优秀面向对象设计”建议了哪些策略? 答:针对接口编程、优先使用对象组合而不是类继承,找到并封装变化点。 4.面向对象系统中功能复用的两种最常用技术是什么? 答:类继承和对象组合,类继承允许你根据其他类的实现来定义一个类的实现。父类的内部细节对子类可见。 类继承是在编译时刻静态定义的,且可直接使用,类继承可以较方便地改变被复用的实现。对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。 5.只根据抽象类中定义的接口来操纵对象有什么好处? 答:1) 客户无须知道他们使用对象的特定类型,只须对象有客户所期望的接口。 2) 客户无须知道他们使用的对象是用什么类来实现的,他们只须知道定义接口的抽象类。 五、应用题(分值15) 公司架构:经理、工程师、技师和后勤人员都是公司的雇员,经理管理工程师、技师和后勤人员。高层经理领导较低级别的经理。典型层次图如下:可以使用哪种设计模式实现公司的层级关系?并说明为什么? 组合模式,第一,其公司关系架构为树形结构;第二,其表示了部分-整体关系(自己扩展)

八种架构设计模式及其优缺点

八种架构设计模式及其优缺点概述(上) 1. 什么是架构 我想这个问题,十个人回答得有十一个答案,因为另外的那一个是大家妥协的结果。哈哈,我理解,架构就是骨架,如下图所示: 人类的身体的支撑是主要由骨架来承担的,然后是其上的肌肉、神经、皮肤。架构对于软件的重要性不亚于骨架对人类身体的重要性。 2. 什么是设计模式

这个问题我问过的面试者不下于数十次,回答五花八门,在我看来,模式就是经验,设计模式就是设计经验,有了这些经验,我们就能在特定情况下使用特定的设计、组合设计,这样可以大大节省我们的设计时间,提高工作效率。 作为一个工作10年以上的老码农,经历的系统架构设计也算不少,接下来,我会把工作中用到的一些架构方面的设计模式分享给大家,望大家少走弯路。总体而言,共有八种,分别是: 1.单库单应用模式:最简单的,可能大家都见过 2.内容分发模式:目前用的比较多 3.查询分离模式:对于大并发的查询、业务 4.微服务模式:适用于复杂的业务模式的拆解 5.多级缓存模式:可以把缓存玩的很好 6.分库分表模式:解决单机数据库瓶颈 7.弹性伸缩模式:解决波峰波谷业务流量不均匀的方法之一 8.多机房模式:解决高可用、高性能的一种方法 3. 单库单应用模式这是最简单的一种设计模式,我们的大部分本科毕业设计、一些小的应用,基本上都是这种模式,这种模式的一般设计见下图:

如上图所示,这种模式一般只有一个数据库,一个业务应用层,一个后台管理系统,所有的业务都是用过业务层完成的,所有的数据也都是存储在一个数据库中的,好一点会有数据库的同步。虽然简单,但是也并不是一无是处。

优点:结构简单、开发速度快、实现简单,可用于产品的第一版等有原型验证需求、用户少的设计。 缺点:性能差、基本没有高可用、扩展性差,不适用于大规模部署、应用等生产环境。 4. 内容分发模式基本上所有的大型的网站都有或多或少的采用这一种设计模式,常见的应用场景是使用CDN技术把网页、图片、CSS、JS等这些静态资源分发到离用户最近的服务器。这种模式的一般设计见下图:

[架构设计]设计模式C++实现--适配器模式

模式定义: 适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。 适配器可以分为类适配器和对象适配器。 类适配器使用多重继承对一个接口与另一个接口进行匹配。 对象适配器依赖于对象组合。 客户使用适配器的过程: 1. 客户通过目标接口调用适配器的方法对适配器发出请求。 2. 适配器使用被适配者接口把请求转换成被施培者的一个或多个调用接口 3. 客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用。 模式结构: 类适配器

Cl ient +speaficRec^jest( ) +request(j 对象适配器 +speaficRequest( ) Adapter 举例 (叫声 为 现在假设你缺少鸭子对象 不能公然拿来使用 UML 设计 用一些火鸡对象(叫声为 distanee )”来冒充。显而易见,因为火鸡的接口 (行为)不同,所以我 们 Gobble gob ”l 飞行输出 ” I ' m flying a short Quae 飞行输出 ”1' m flying!,想 Client Target p 1 n +request()

Adapter +quack() 编程实现及执行结果: [cpp] view pla in copy 1. #in clude 2. 3. using namespacStd; 4. //定义鸭子类 5. class Duck 6. { 7. public : 8. virtual void quack(){}; 9. virtual void fly(){}; 10. }; 11. //定义绿头鸭 12. class MallardDuck : public Duck 13. { 14. public : 15. void quack() 16. { 17. cout << "Quack"<< endl; 18. } 19. 20. void fly() 21. { 22. cout << "I'm flyi ng" << endl; Di jck Turkey +quaek^ +flyO +gobble() +fly()

浅析23种软件设计模式

浅析23种软件设计模式 1、工厂模式:客户类和工厂类分开。消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。 2、建造模式:将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。 3、工厂方法模式:核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。 4、原始模型模式:通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。原始模型模式允许动态的增加或减少产品类,产品类不需要非得有任何事先确定的等级结构,原始模型模式适用于任何的等级结构。缺点是每一个类都必须配备一个克隆方法。 5、单例模式:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。 6、适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。 7、桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。 8、合成模式:合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的树结构的模式。合成模式把部分与整体的关系用树结构表示出来。合成模式使得客户端把一个个单独的成分对象和由他们复合而成的合成对象同等看待。 9、装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。 10、门面模式:外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。 11、享元模式:FL YWEIGHT在拳击比赛中指最轻量级。享元模式以共享的方式高效的支持大量的细粒度对象。享元模式能做到共享的关键是区分内蕴状态和外蕴状态。内蕴状态存

设计模式主要分三个类型

设计模式主要分三个类型:创建型、结构型和行为型。 其中创建型有: 一、Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点 二、Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。 三、Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。 四、Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。 五、Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。 行为型有: 六、Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。 七、Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。 八、Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。 九、Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。 十、State,状态模式:允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。 十一、Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。 十二、China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系 十三、Mediator,中介者模式:用一个中介对象封装一些列的对象交互。 十四、Visitor,访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。 十五、Interpreter,解释器模式:给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 十六、Memento,备忘录模式:在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。 结构型有: 十七、Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。 十八、Facade,外观模式:为子系统中的一组接口提供一致的界面,fa?ade 提供了一高层接口,这个接口使得子系统更容易使用。 十九、Proxy,代理模式:为其他对象提供一种代理以控制对这个对象的访问

设计模式C++实现(3)——适配器模式

设计模式C++实现(3)——适配器模式 分类:设计模式2011-08-06 17:21 2163人阅读评论(7) 收藏举报软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最近看设计模式的书,对于每个模式,用C++写了个小例子,加深一下理解。主要参考《大话设计模式》和《设计模式:可复用面向对象软件的基础》(DP)两本书。本文介绍适配器模式的实现。 DP上的定义:适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。它包括类适配器和对象适配器,本文针对的是对象适配器。举个例子,在STL中就用到了适配器模式。STL实现了一种数据结构,称为双端队列(deque),支持前后两段的插入与删除。STL实现栈和队列时,没有从头开始定义它们,而是直接使用双端队列实现的。这里双端队列就扮演了适配器的角色。队列用到了它的后端插入,前端删除。而栈用到了它的后端插入,后端删除。假设栈和队列都是一种顺序容器,有两种操作:压入和弹出。下面给出相应的UML图,与DP上的图差不多。 根据上面的UML图,很容易给出实现。 [cpp]view plaincopyprint? 1.//双端队列 2.class Deque

3.{ 4.public: 5.void push_back(int x) { cout<<"Deque push_back"<

深入浅出Java设计模式之适配器模式

通常,客户类(clients of class)通过类的接口访问它提供的服务。有时,现有的类(existing class)可以提供客户类的功能需要,但是它所提供的接口不一定是客户类所期望的。这是由于现有的接口太详细或者缺乏详细或接口的名称与客户类所查找的不同等诸多不同原因导致的。 在这种情况下,现有的接口需要转化(convert)为客户类期望的接口,这样保证了对现有类的重用。如果不进行这样的转化,客户类就不能利用现有类所提供的功能。 适配器模式(Adapter Pattern)可以完成这样的转化。适配器模式建议定义一个包装类,包装有不兼容接口的对象。这个包装类指的就是适配器(Adapter),它包装的对象就是适配者(Adaptee)。 适配器提供客户类需要的接口,适配器接口的实现是把客户类的请求转化为对适配者的相应接口的调用。换句话说:当客户类调用适配器的方法时,在适配器类的内部调用适配者类的方法,这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于借口不兼容而不能交互的类可以一起工作(work together)。 在上面讨论的接口: (1)不是指在JAVA编程语言中接口的概念,虽然类的接口可以通过JAVA借扩来定义。 (2)不是指由窗体和GUI控件所组成的GUI应用程序的用户接口。 (3)而是指类所报漏的,被其他类调用的编程接口, 类适配器(Class Adapter)VS对象适配器(Object Adapter) 适配器总体上可以分为两类??类适配器(Class Adapter)VS对象适配器(Object Adapter) 类适配器: 类适配器是通过继承类适配者类(Adaptee Class)实现的,另外类适配器实现客户类所需要的接口。当客户对象调用适配器类方法的时候,适配器内部调用它所继承的适配者的方法。 对象适配器: 对象适配器包含一个适配器者的引用(reference),与类适配器相同,对象适配器也实现了客户类需要的接口。当客户对象调用对象适配器的方法的时候,对象适配器调它所包含的适配器者实例的适当方法。

相关主题
文本预览
相关文档 最新文档