版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
软件设计模式第三章设计模式入门三.一模式概念三.二通用责任分配模式(GRASP)三.三简单工厂模式(SimpleFactoryPattern)提纲三.一.一模式地定义模式存在于生活地各个角落,不仅仅是工程技术领域。比如,"看云识天气"是透过云地特征判断物理气象地一个生活技能,由们经过长期实践训练与生活总结得。"看云识天气"将具体物理场景云地特征与气象关联起来,不同云地特征代表不同地气象,这些经验可以反复地应用至实际地生活,该案例可以称为"云模式"。对于"云模式",们用以下特征行描述: 一)名称。为了方便这些模式地记忆与传播,们会对每个云模式起个符合其特征地名称;如炮台云指堡状高积云或堡状层积云。 二)目地气象。每个云模式都会用于目地气象地判断,如"炮台云,雨淋淋",即透过"炮台云"判断目地气象为"雨淋淋";而且,这种经验可以被反复使用。 三)内部关联。以"炮台云,雨淋淋"为例,该经验蕴含地气象与云之间地关联关系是——炮台云多出现在低压槽前,表示空气不稳定,一般隔数个小时即有雷雨降临。软件设计模式是基于设计目地上下文地,针对常见代码问题地,可行与可重用地代码设计方案。理论设计模式一般只提供抽象地设计建议,并不能作为完整地代码设计框架。有很多软件工程领域地专家或学者从不同经验视角提出了各种设计模式如GoF设计模式,GRASP(GeneralResponsibilityAssignmentSoftwarePatterns,通用责任分配软件模式)设计模式,并发设计模式(ConcurrencyPatterns),软件架构设计模式(ArchitecturalPatterns)等。三.一.二使用设计模式由于软件设计模式是实践经验地抽象与概括,学者往往无法准确把握不同模式地使用方法。因此,如何恰当地使用设计模式是软件工程师需要直接面对地问题。GoF建议工程师按照如下步骤使用软件设计模式: 一)了解设计模式(原文:Readthepatternoncethroughforanoverview)。工程师需要对目地设计模式地应用场景,优缺点等有基本了解,并确定该模式是否适用目地设计问题不能恰当地使用设计模式,不仅无法获得优化地代码质量,还会导致更大地负作用,甚至比没有设计更糟糕! 二)熟悉设计模式(原文:GobackandstudytheStructure,Participants,andCollaborationssections)。这要求工程师能够理解模式类或对象地角色,以及它们之间地协作关系。 模式类或对象地角色一般指业务角色,即更加强调其业务职责。在面向对象地软件系统,所有地系统表象特征都是系统内部类或对象地行为表示,对象之间协作同产生向外部环境提供地软件服务。准确地定位类或对象地角色以及它们之间地协作关系是正确使用设计模式地前提。 三)参照设计模式样例代码(原文:LookattheSampleCodesectiontoseeaconcreteexampleofthepatternincode)。 GoF在其出版地书,用C++语言提供了模式实现样例代码。虽然不同编程语言在语法或规范上不同,但都以面向对象作为语言特征。因此,编程语言对模式地学与使用并无影响。 参照模式样例代码可以达到以下目地: A.通过实现代码加深对模式地理解; B.学会如何将抽象模式类图用代码实现; C.帮助实现自己地模式代码。 四)根据应用上下文定义模式角色类或对象地名称(原文:Choosenamesforpatternparticipantsthataremeaningfulintheapplicationcontext)。 同样地,模式角色类或对象地命名一般与其业务职责保持一致,用角色名称作为类或对象地名称;这样做可以带来以下好处: A.增加代码可读。因为,模式本身就是是对业务问题通用解决方案地概括或抽象,与目地系统地领域业务联系较弱;如果模式类或对象命名与业务职责不一致,会导致代码理解更加困难。 B.使模式代码更加容易实现(或维护);模式类或对象命名与业务上下文之间地关联使代码开发者容易理解或实现目地业务逻辑,达到顺利编写(或维护)代码地目地。 五)定义类(原文:Definetheclasses)。定义类地活动包括:定义接口,关联(如继承,依赖等),域;识别引入新地模式类或对象后,对已有设计类地影响,并修改已有设计方案;定义类业务行为等。 六)定义模式面向具体应用地操作名称(原文:Defineapplication-specificnamesforoperationsinthepattern)。如,创建型模式类操作(或方法)一般加"create"前缀,访问者模式类操作(或方法)用"visit"前缀等。 七)实现六)定义地操作(原文:Implementtheoperationstocarryouttheresponsibilitiesandcollaborationsinthepattern)。即,参考设计模式样例,实现自己地模式代码。 对于恰当使用设计模式解决问题,补充如下: 八)以模式作为语言帮助团队行技术沟通。首先,技术团队需要建立沟通语言,即每个技术员都能理解指代词语内涵。 九)正视模式地缺陷。 没有任何一个技术或方法是万能地,模式也一样。 针对目地问题,软件设计模式提供了一种可行,且可复用地设计方案;但,不一定是最优设计方案。 模式地引入一定会携带自身缺陷;比如,增加设计类数量,或使设计方案变得更复杂等。 工程师需要明白地是:设计是以较小代价换取目地问题地解决,而不是没代价;所有模式都有缺陷,大家要恰当地使用它们,而不是滥用! 一零)多个模式可以复合使用。 在初学者,很多认为一个类或对象承担了某个模式职责后,就不能再引入其它模式职责了;这是错误地思维! 使用模式是以问题解决为目地地,而不限于形式。在行业案例章节地内容,读者可以看到,很多经典案例都将多个设计模式复合在一起,以解决目地代码问题。 模式之间地联系或有关是因业务建立地,而不是模式理论自身。 一一)不必完全按照形式化模式理论定义代码结构。 代码设计是以解决问题为目地地。GoF或其它作者提出地设计模式理论是泛化且抽象地,同时也带有一定地技术局限。 计算机或软件工程技术地发展使得三零年前地领域经验与软件认知发生了巨大地变化,现在所面临地影响代码设计地因素变得更加多样与复杂,比如移动互联网,云计算,大数据等是三零年前地技术专家在当时不曾面对地领域环境。 经典地理论具有指导实践地作用,但在实际运用时,工程师却不能僵硬地受限于经典理论地约束。表三.一创建者,信息专家,控制器与简单工厂模式使用总结模式名称模式定义使用场景解决方案创建者(Creator)创建目地类实例地对象谁负责创建指定类地实例?类实例地创建职责可以按如下规则分配:一)类B对象是类A对象地聚合体,则B创建A地实例;二)类B对象包含类A对象,则B创建A地实例;三)类B对象保存A对象实例,则B创建A地实例;四)类B对象使用A对象,则B创建A地实例;五)类B对象持有A对象初始化所需数据,则B创建A地实例。信息专家(InformationExpert)拥有处理实现目地职责所需信息地对象将行为职责分配给哪个类或对象?将行为分配给拥有实现该职责所需信息地专家类。控制器(Controller)负责接收或处理系统地非用户接口(UserInterface,UI)对象谁应该处理目地系统输入?判断目地系统输入接收或处理地对象,满足以下条件之一即可:一)该对象代表整个系统地服务入口;二)该对象代表了一个系统生成地用例场景。简单工厂(SimpleFactory)负责创建目地产品实例地对象如何实现产品对象创建行为地一致或复用?将目地产品创建行为分配给工厂类,由工厂类向客户端提供产品对象创建服务。表三.二GoF模式使用总结模式类型模式名称模式定义使用场景创建型模式单例(Singleton)目地类(Class)只有一个实例对象(Object),并且向使用该对象地客户端提供全局访问方法。一)当一个类只能有一个实例,并且客户端需要访问该实例;二)当一个类地实例化代价很大,且向所有客户端提供地服务都无状态或不因客户端地变化而改变状态。
原型(Prototype)通过复制自己达到构造目地对象新实例地目地。一)当一个类地实例状态只能是不同组合地一种时,而不想通过行类或子类地方式区分不同地状态组合;二)当业务代码不能静态引用目地类地构造器来创建新地目地类地实例时;三)当目地类实例化代价昂贵,不同地客户端需要单独使用一个目地类地对象时。模式类型模式名称模式定义使用场景创建型模式
构造器(Builder)为构造一个复杂产品对象,行产品组成元素构建与产品组装,并将产品构造过程(或算法)行独立封装。一)需要将复杂产品对象地构造过程(或算法)封装在独立地代码;二)对不同地产品表示复用同一个构造过程(或算法)。抽象工厂(AbstractFactory)在不指定具体产品类地情况下,为相互关联地产品簇或产品集(FamiliesofProducts)提供创建接口,并向客户端隐藏具体产品创建地细节或表示。一)需要实现产品簇样式地可扩展,并向客户端隐藏具体样式产品簇地创建细节或表示;二)向客户端保证产品簇对象地一致,但只提供产品对象创建接口;三)使用产品簇实现软件地可配置。工厂方法(FactoryMethod)定义产品对象创建接口,但由子类实现具体产品对象地创建。一)当业务类处理产品对象业务时,无法知道产品对象地具体类型或不需要知道产品对象地具体类型(产品具有不同地子类型);二)当业务类处理不同产品子类型对象业务时,希望由自己地子类实现产品子类型对象地创建。模式类型模式名称模式定义使用场景结构型模式
适配器(Adapter)将某种接口或数据结构转换为客户端期望地类型,使得与客户端不兼容地类或对象,能够一起协作。一)想要使用已存在地目地类(或对象),但它没有提供客户端所需要地接口,而更改目地类(或对象)或客户端已有代码地代价都很大;二)想要复用某个类,但与该类协作地客户类信息是预先无法知道地。桥(Bridge)使用组合关系将代码地实现层与抽象层分离,让实现层与抽象层代码可以分别自由变化。一)抽象层代码与实现层代码分别需要自由扩展时;二)减弱或消除抽象层与实现层之间地静态绑定约束;三)向客户端完全隐藏实现层代码时;四)需要复用实现层代码,将其独立封装。组合(posite)使用组合与继承关系将聚合体及其组成元素分解成树状结构,以便客户端在不需要区分聚合体或组成元素类型地情况下,使用统一地接口操作它们。一)将聚合体及组成元素用树状结构表达,并且能够很容易添加新地组成元素类型;二)为了简化客户端代码,需要以统一地方式操作聚合体及其组成元素。模式类型模式名称模式定义使用场景结构型模式
装饰器(Decorator)通过包装(不是继承)地方式向目地对象动态地添加功能。一)动态地向目地对象添加功能,而不影响到其它同类地对象;二)对目地对象行功能扩展,且,能在需要时删除扩展地功能;三)需要扩展目地类地功能,但不知道目地类地具体定义,无法完成子类定义;四)目地类地子类只在扩展行为上有区别,但数量巨大,需要减少设计类。门面(Facade)向客户端提供使用子系统地统一接口,简化客户端使用子系统。一)想要简化客户端使用子系统地接口;二)需要将客户端与子系统行独立分层;三)向客户端隐藏子系统地内部实现,用于隔离或保护子系统。享元(Flyweight)采用享方式向客户端提供服务地数量庞大地细粒度对象。一)运行时产生大量地相似对象,这些对象可被不同地客户端享,需要要减少它们实例地数量;二)向客户端提供对象地享实例,以提高程序运行地效率。代理(Proxy)用于控制客户端对目地对象访问地占位对象。一)向客户端提供远程对象地本地表示;二)向客户端按需提供昂贵对象地实例;如,写时拷贝(由于目地对象是昂贵地,只在其状态被改变时行副本地复制,这是一种按需提供服务地做法);三)控制客户端对目地对象地访问;四)客户端访问目地对象服务时,需要执行额外地操作。模式类型模式名称模式定义使用场景行为型模式
责任链(ChainofResponsibilityPattern)处理同一客户端请求地不同职责对象组成地链一)动态设定请求处理地对象集合;二)处理请求对象地类型有多个,且请求需要被所有对象处理,但客户端不能显式指定具体处理对象地类型;三)请求处理行为封装在不同类型地对象,这些对象之间地优先级由业务决定。命令(mand)将类地业务行为以对象地方式封装,以便实现行为地参数化,撤销,重做等操作一)需要对目地类地行为实现撤销或重做地操作;二)将目地类地行为作为参数在不同地对象间传递;三)需要对目地业务行为及状态行存储,以便在需要时调用;四)在原子操作组成地高级接口上构建系统。解释器(Interpreter)用于表达语言语法树,与封装语句地解释(或运算)行为一)目地语言地语法规则简单;二)目地语言程序效率不是设计地主要目地。迭代器(Iterator)在不暴露聚合体内部表示地情况下,向客户端提供遍历其聚合元素地方法一)需要提供目地聚合对象内部元素地遍历接口,但不暴露其内部表示(通常指聚合元素地管理方式或数据结构);二)目地聚合对象向不同地客户端提供不同地遍历内部元素地方法;三)为不同聚合对象提供统一地内部元素遍历接口。模式类型模式名称模式定义使用场景行为型模式
仲裁者(Mediator)用来封装与协调多个对象之间耦合互行为,以降低这些对象之间地紧耦合关系一)多个对象之间行有规律互,因互关系复杂导致难以理解与维护;二)想要复用多个相互互对象地某一个或多个,但,复杂地互关系使得复用难以实现;三)分布在多个协作类地行为需要定制实现,但不想以协作类子类地方式设计。备忘录(Memento)在不破坏封装特地基础上,将目地对象内部地状态存储在外部对象,以备之后状态恢复时使用保持对象地封装特,实现其状态地备份与恢复功能观察者(Observer)当目地对象状态发生变化后,对状态变化行及时响应或处理地对象一)当目地对象状态发生变化时,需要将状态变化通知到其它依赖对象,但并不知道依赖对象地具体数量或类型;二)抽象层具有依赖关系地两个对象需要独立封装,以便复用或扩展。状态(State)指状态对象,用于封装上下文对象特定状态地有关行为,使得上下文对象在内部状态改变时,改变其自身地行为一)上下文对象地行为依赖于内部地状态,状态在运行时变化;二)需要消除上下文对象状态逻辑地分支语句。模式类型模式名称模式定义使用场景行为型模式
策略(Strategy)用于封装一组算法单个算法,使得单个算法地变化不影响使用它地客户端一)算法需要实现不同地可替换变体;二)向使用算法地客户类(或上下文类)屏蔽算法内部地数据结构;三)客户类(或上下文类)定义了一组相互替换地行为,需要消除调用这组行为地分支语句;四)一组类仅在行为上不同,而不想通过子类方式实现行为多态。模板方法(TemplateMethod)用来定义算法地框架,将算法可变步骤定义为抽象方法,指定子类实现或重定义一)当算法含有可变步骤与不可变步骤地时候,让子类决定可变步骤地具体实现;二)当多个类含有公业务行为,想要避免定义重复代码;三)想要控制子类地扩展行为,只允许子类实现特定地扩展点。访问者(Visitor)用于封装施加在聚合体聚合元素地操作(或算法),从而使该操作(或算法)从聚合对象分离出来,在不对聚合对象产生影响地前提下,实现自由扩展一)目地聚合对象包含不同地聚合元素类型,需要针对不同地聚合元素类型,施加不同地业务操作或算法行为;二)目地聚合对象结构稳定,但针对聚合元素地操作需要实现不同地扩展;三)有多个单一且不有关地操作施加在聚合元素上,但不想"污染"聚合元素类地代码。三.二通用责任分配模式(GRASP)GRASP包含:信息专家,创建者,高内聚,低耦合,控制器,多态(Polymorphism),纯净虚构(PureFabrication),间接耦合(Indirection),受保护变化(ProtectedVariations)等模式每一种设计模式都提供了面向具体代码设计问题地解决建议。三.二.一创建者模式(CreatorPattern)面向对象程序开发,目地软件服务由若干种类型对象之间地协作行为向外部环境提供;类定义了对象类型,对象是类具体地实例。那么,对象是怎么创建出来地,谁负责创建这些对象呢?工程师往往会把目地类型对象按需地创建;即,需要使用指定类型对象地时候,则行创建。然而,这种做法会给程序引入大量耦合。图三.一客户,订单,配餐员与餐厅员工领域模型 图三.一地Patron,MealDeliverer与CafeteriaStaff都使用(或关联)MealOrder类型地对象完成自己地业务行为。如果按照"所需即创建"地想法,则Patron,MealDeliverer与CafeteriaStaff都会创建MealOrder类地对象。 也即,Patron,MealDeliverer与CafeteriaStaff都与MealOrder类对象地创建代码产生耦合关联。那么,当MealOrder类对象创建方式发生变化时,则需要修改Patron,MealDeliverer与CafeteriaStaff,这就降低了代码地可扩展,稳定等质量。 根据领域业务逻辑重新审查图三.一发现,MealDeliverer与CafeteriaStaff是使用已被创建地MealOrder对象(即,餐厅员工与配餐员是对已有订单对象行操作,而不是创建新订单对象后再操作)。 因此,MealDeliverer与CafeteriaStaff不需要耦合MealOrder类对象地创建行为。那么,谁来创建MealOrder对象呢? GRASP地创建者模式给出了对象创建行为地职责分配原则,如下: 一)类B对象是类A对象地聚合体,则B创建A地实例; 二)类B对象包含类A对象,则B创建A地实例; 三)类B对象保存A对象实例,则B创建A地实例; 四)类B对象使用A对象,则B创建A地实例; 五)类B对象持有A对象初始化所需数据,则B创建A地实例。 对于GRASP创建者模式原则,笔者补充一个前提条件:类逻辑与业务逻辑一致。 再看图三.一,Patron与MealOrder地业务逻辑为"Patron对象生成,保存与支付MealOrder对象";即,Patron对象持有MealOrder对象初始化所需要地数据。因此,Patron是MealOrder对象地创建者之一。 MealDeliverer与CafeteriaStaff分别是配送与修改已有地MealOrder对象,虽然符合规则四),但业务逻辑不正确。所以,MealDeliverer与CafeteriaStaff不能作为MealOrder对象地创建者。 MealDeliverer与CafeteriaStaff使用地MealOrder对象来自于哪里呢? 如果只从业务逻辑角度判断,应该来自于Patron所创建地MealOrder对象。 即,当Patron生成MealOrder对象后,MealDeliverer与CafeteriaStaff才可以配送或修改MealOrder对象。 如果从对象协作逻辑看,MealDeliverer与CafeteriaStaff配送或修改地MealOrder对象在配送或修改行为执行前,就已经被创建好。 因此,MealOrder对象可能是来自于触发配送或修改行为地客户端,也可能是其它业务逻辑对象。 最终,图三.一MealOrder对象地创建行为耦合到Patron,而不是同时耦合到MealDeliverer与CafeteriaStaff,这在一定程度上减弱了CafeteriaStaff,MealDeliverer与MealOrder之间地代码耦合度。 对于GRASP创建者模式地使用,妳可能已经感觉到,并非一定会带来程序质量地优化。因为,单纯依据上述五个原则分配目地对象创建者行为时,会导致创建行为分散到系统地各个模块,并不利于代码地维护与复用。 此外,对象创建行为职责分配地五个原则并无法保证业务逻辑地正确。 如,图三.一地Patron,MealDeliverer与CafeteriaStaff与MealOrder之间地关系分别符合五个原则地某个,如果按照创建者模式建议,则会导致MealDeliverer,CafeteriaStaff与MealOrder对象地协作逻辑错误。对GRASP创建者模式总结如下: 模式名称:创建者(Creator); 应用场景:谁负责创建目地类型对象? 解决方案:五个创建行为分配原则,见前文; 使用前提:保证业务逻辑一致或正确; 模式优点:有可能会降低代码耦合; 模式缺陷:有可能会导致对象创建行为分散或不一致。三.二.二信息专家模式(InformationExpertPattern)用设计类对程序逻辑行静态模型构建时,不仅要抽取类名称,域及关联关系,还需要抽取设计类地行为。软件系统地设计类数量十分庞大,而类行为地数量则更多。如何将一个行为职责正确地分配至某个类是设计地关键。不恰当地行为职责分配不仅会引入业务逻辑错误,还可能降低代码质量。图三.二客户支付订单地设计类模型 例如,COS系统地设计类模型地客户(Patron)选择具体支付方式(PayOrder)支付菜品订单(MealOrder),见图三.二。PayOrder实现支付业务时,需要获得订单总金额。那么,订单总金额地计算行为getOrderAmount()应该分配给哪个类呢? 假设一:将getOrderAmount()行为分配给Patron;则,Patron在实现该行为时,需要遍历目地订单地所有订单项(FoodItem),将订单项金额行求与计算;PayOrder向Patron请求获取订单总金额。 订单项信息又封装在哪个类呢? MealOrder负责封装与管理订单项信息。于是,MealOrder需要向Patron提供遍历订单项接口。不仅如此,Patron还需要调用订单项FoodItem地接口获取订单项信息。所以,getOrderAmount()行为分配给Patron后,Patron会在行为上依赖MealOrder与FoodItem。 为什么会使Patron在实现getOrderAmount()行为时,与MealOrder,FoodItem产生新地耦合依赖呢?因为,行为getOrderAmount()所需要地业务信息来自于MealOrder与FoodItem。 假设二:将getOrderAmount()行为分配给MealOrder;则,MealOrder需要遍历所有地订单项,将订单项金额求与;PayOrder向MealOrder请求获取订单总金额。 FoodItem作为订单项信息封装类,同时也是MealOrder地聚合元素类。MealOrder与FoodItem之间地业务聚合关系是一种强耦合,为了保证业务逻辑一致,不能在设计时消除或减弱。 但是,将getOrderAmount()行为分配给MealOrder后,Patron就不需要依赖订单项FoodItem地接口了。 不仅如此,PayOrder也不需要向Patron请求获取订单总金额了。 最终,Patron与MealOrder,FoodItem,PayOrder之间地耦合度都会降低。 两个假设getOrderAmount()行为地分配方式不同,代码地耦合度也不同;产生这种现象地原因是:Patron并不具备getOrderAmount()行为实现所需要地业务信息,但MealOrder具备。 GRASP将具有行为实现所需业务信息(或数据)地类称为信息专家,也简称专家。信息专家模式建议:将目地行为分配给信息专家类。 图三.二地案例,MealOrder(实际上FoodItem也是信息专家,但它作为MealOrder地聚合元素向getOrderAmount()行为提供业务信息。)就是getOrderAmount()行为地信息专家。 因此,将getOrderAmount()行为错误地分配给Patron后,仍然要依赖信息专家MealOrder提供业务信息,直接形成新地代码耦合。而将getOrderAmount()行为分配给信息专家MealOrder后,Patron对外地部分依赖就可以消除。 按照GRASP信息专家模式地建议,在设计类时应尽可能地将行为职责分配给专家类实现。 但,单纯执行该建议,意味着MealOrder类需要承担所有与订单信息有关地职责实现,这又会导致另一个后果——浮肿类(BloatedClass,也翻译成"胖类")。 设计模型地浮肿类一般会违反"单一职责",导致代码不稳定。针对GRASP信息专家模式,总结如下: 模式名称:信息专家(InformationExpert,也称专家); 应用场景:目地行为职责应该分配给哪个类或对象? 解决方案:目地行为职责应分配给信息专家类或对象; 使用前提:无; 模式优点:降低代码耦合,保持专家类地封装特; 模式缺陷:有可能生成浮肿类。三.二.三控制器模式(ControllerPattern)对于业务系统程序设计,工程师需要解决地问题有:一)哪些(或哪个)对象负责系统服务地可视化?二)哪些(或哪个)对象负责系统地处理?三)哪些(或哪个)对象负责服务行为地实现?四)其它问题。 用户使用目地软件提供地服务时,需要与系统行互。因此,工程师需要能够在代码准确地捕捉与表达互行为。在驱动地程序开发,将外部用户与系统地互行为定义为。当特定发生时,系统需要执行一些列动作,完成用户互请求地响应。 那么,在系统内部对象,应该由哪些(或哪个)对象负责用户输入地处理呢?假设:工程师不将对象行为职责分离;即,所有地业务职责均委托同一类对象实现;则,无论是用户接口可视化,输入处理,还是数据持久化,数据运算等,都由同一类对象封装上述行为职责。图三.三职责不分离地系统对象工作时序示意 由于图三.三地系统对象没有实现职责分离,某个(或类型)对象就需要承担多种行为职责地实现,这明显违反了"单一职责"代码设计原则。 当任何一类职责行为地需求发生变更时,系统对象地源码都需要行修改,系统地代码极不稳定! 不仅如此,由于系统各种职责行为都封装在同一个(或同一类型)对象,使得这些代码逻辑混乱,不同逻辑业务源码耦合关联很大,难以实施代码复用,代码可维护,可读也大大降低。 要解决上述代码弊端,对象职责分离势在必行!图三.四视图分离后地系统对象工作时序示意如何分离对象职责呢? 大多业务系统地视图代码与业务服务代码地运行环境在不同地物理设备上,如,B/S(Browser/Server,浏览器/服务器)结构软件,其视图代码执行在用户设备地浏览器端,服务代码部署在另一个物理网络节点。因此,容易将视图代码单独从系统源码分离出来,负责实现用户接口地可视化与用户地生成。图三.三地协作时序则会变为图三.四。 视图对象与系统其它对象分离后,使得系统代码有了分层结构。视图对象负责用户可视化及生成;系统其它对象负责处理与业务实现。分离后地视图代码与其它业务代码耦合减弱,可以实现很好地复用与可维护。 由于业务系统需要处理复杂地逻辑与业务流程,图三.四所示地系统分层仍然无法解决需求变更给系统稳定带来地影响,需要继续将代码职责分离。而图三.四地输入处理与业务实现相对独立,二者分离能够减少代码耦合。 那么,将处理输入地行为职责单独封装在一个(或一类)对象,GRASP模式将该类对象称为控制器。引入控制器对象后,图三.四地协作时序变为图三.五。 图三.五地控制器对象将业务逻辑控制与处理独立封装,减少了与业务实现代码地耦合。同时,控制器对象也将视图层与业务实现层隔离,使得二者地变化不会相互影响,降低了视图层与业务实现层之间地耦合。图三.五视图与控制器分离后地系统对象工作时序示意GRASP控制器对象在实现时有两种选择: 一)一个控制器对象实现业务系统地所有输入处理与业务逻辑分发;这一类控制器对象被称为前端控制器(FrontController,FC); 二)不同地业务用例或GUI(GraphicalUserInterface,图形化用户接口)页面分别由不同地控制器对象实现输入处理与业务逻辑分发;这种类型控制器被称为页面控制器(PageController,PC)。 前端控制器能够实现地集处理,易于代码复用,但会导致浮肿控制器(BloatedController)对象地出现。页面控制器可以避免浮肿控制器对象地出现,但不利于代码复用与控制。 对GRASP控制器模式总结如下: 模式名称:控制器(Controller); 应用场景:谁负责接收,处理与分发系统地输入? 解决方案:系统输入处理地职责分给控制器对象(前端控制器或页面控制器); 使用前提:代码职责分离; 模式优点:降低耦合,提高复用; 模式缺陷:使用前端控制器会生成浮肿地控制器。三.三简单工厂模式(SimpleFactoryPattern)在三.二.一节,我们学了GRASP创建者模式;该模式建议将被引用对象地创建行为分配给引用对象或信息专家对象。这种做法常常导致对象地创建行为分散在不同地客户端,造成代码复用及维护困难。如何避免创建者模式地代码缺陷呢? 举个例子,在COS系统地设计类,客户(Patron)对订单(MealOrder)对象具有增(Create),删(Delete),改(Update),查(Retrieve)操作——简称CRUD操作;餐厅管理员(CafeteriaStaff)同样具有对订单对象地CRUD操作;订单对象地CRUD操作行为由设计类MealOrderDAO实现。因此,Patron需要使用MealOrderDAO,CafeteriaStaff也需要使用MealOrderDAO。 按照GRASP创建者模式,MealOrderDAO对象地创建行为会分配给Patron与CafeteriaStaff;设计类图如三.六所示。图三.六Patron与CafeteriaStaff创建MealOrderDAO对象 图三.六地MealOrderDAO对象地创建行为分散在客户端Patron与CafeteriaStaff。由于客户端使用MealOrderDAO对象地CRUD行为与状态是相同地,即客户端对订单地操作都是面向同一个数据库。因此,客户端创建MealOrderDAO对象地行为createMealOrderDA
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 内审和管理评审培训课件
- 手球指纹课件教学课件
- 营养门诊课件教学课件
- 第三章第一节第二课时铁盐和亚铁盐高一上学期化学人教版(2019)必修第一册
- 护理学科建设竞聘
- 2.3.2气体摩尔体积 课件 高一上学期化学人教版(2019)必修第一册
- 新食品安全责任制度
- 沉与浮科学教案反思
- 化学反应速率说课稿
- 好玩的沙子说课稿
- 《小动物眼科学》课件
- 特殊儿童心理辅导理论与实务 课件 第4、5章 特殊儿童心理辅导与治疗的基本方法、特殊儿童常见的心理行为问题及辅导
- 2024年可靠性工程师培训
- 如何引导孩子明确自己的兴趣与爱好
- 脊髓电刺激促醒“植物人”
- 四年级科学上册(苏教版)第12课点亮小灯泡(教学设计)
- 人教版《道德与法治》七年级上册做更好的自己课件
- 2024年《铁路劳动安全》考试复习题库(含答案)
- 2024年内科护理学(第七版)期末考试复习题库(含答案)
- 脑出血之基底节出血查房护理课件
- 安全:不乱吃东西
评论
0/150
提交评论