面向对象分析和设计讲座9.细化迭代2更多模式_第1页
面向对象分析和设计讲座9.细化迭代2更多模式_第2页
面向对象分析和设计讲座9.细化迭代2更多模式_第3页
面向对象分析和设计讲座9.细化迭代2更多模式_第4页
面向对象分析和设计讲座9.细化迭代2更多模式_第5页
已阅读5页,还剩92页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第9讲细化迭代2:更多模式内容迭代2GRASP模式GoF模式11/25/202321.迭代2的需求和重点1.1迭代2的重点基本对象设计使用模式来创建稳健的设计应用UML使模型可视化11/25/2023411/25/202351.2从迭代1到迭代2在迭代1所有软件都已经被充分地测试客户定期地参与对已完成部分的评估已经对系统(这里的系统也包括所有子系统)进行了完整的集成和固化,使其成为基线化的内部版本11/25/202361.3迭代2需求NextGenPOS支持第三方外部服务的变化,例如,能够与不同的税金计算器相连接复杂的定价规则,可更换的业务规则需要进行设计,使得在销售总额变化时刷新GUI窗口11/25/20237由于这些需求,我们要在迭代2中对处理销售用例进行修订,但是实现了更多场景对面向分析的对象的修改在此轮迭代中也是需要的Use-CasesSSDsDomainModel11/25/202382.GRASP:MorePatternsForAssigningResponsibilities我们学习了什么?信息专家创建者高内聚低耦合控制器11/25/202310我们还需要学习?多态(Polymorphism)间接性(Indirection)纯虚构(PureFabrication)防止变异(ProtectedVariation)11/25/2023112.1多态问题如何处理基于类型的选择?“If-then-else”;“select-case”如何创建可插拔的软件构件?11/25/202313解决方案当相关选择或行为随类型(类)有所不同时,使用多态为变化的行为类型分配职责11/25/202314例子支持多种外部的第三方税金计算器它们具有不同技术实现的不同的TCPsocketSOAPinterfaceJavaRMIinterface11/25/202315TaxMasterAdaptergetTaxes(Sale):ListofTaxLineItemsGoodAsGoldTaxProAdaptergetTaxes(Sale):ListofTaxLineItems<<interface>>ITaxCalculatorAdaptergetTaxes(Sale):ListofTaxLineItemsByPolymorphism,multipletaxcalculatoradaptershavetheirownsimilar,butvaryingbehaviorforadaptingtodifferentexternaltaxcalculators.<???>Adapter......11/25/202316UMLNotationGoodAsGoldTaxProAdaptergetTaxes(Sale):ListofTaxLineItems<<interface>>ITaxCalculatorAdaptergetTaxes(Sale):ListofTaxLineItemsINTERFACENOTATIONINTERFACENOTATIONInterfaceimplementationisillustratedwithadashedlineandalargeunfilledarrowpointingtotheinterfacefromtheimplementingclass.the<<interface>>elementinguillemetsiscalledaUMLstereotypeReturnorparametertypesthatrepresentacollectioncanbespecifiedinanysyntax,butthisisthegenerallyacceptedcommonUMLstyle.11/25/202317禁忌不要为那些假想中的变化添加太多的多态11/25/202318优点易于增加新变化所需的扩展无需影响客户便能够引入新的实现11/25/2023192.2纯虚构(PureFabrication)问题面向对象设计依据真实世界中的概念来表示软件类但是软件并非真实的世界我们需要通过领域层对象来克服低内聚或者耦合低复用11/25/202321解决方案对人为制造的类分配一组高内聚的职责,该类并不代表问题领域的概念-虚构的事物,用以支持高内聚、低耦合和复用11/25/202322例子为了保存Sale

的实例到关系数据库基于信息专家的考虑,存在理由将责任分配给Sale

类自己.但是考虑如下含义:需要大量的数据库操作,这将使Sale

变得非内聚Sale

类必须与关系数据库接口耦合,这样增加了耦合将对象保存到关系数据库中是一个普遍的任务-它可以重用11/25/20232311/25/202324讨论对象的设计可以广泛的分成两组表示解析(Representationaldecomposition)行为解析(Behavioraldecomposition)11/25/202325优点支持高内聚增加了潜在的复用性11/25/202326禁忌不要过度使用它将导致非O-O的系统11/25/2023273.间接性(Indirection)问题为了避免两个或多个事物之间的直接耦合,应该如何分配职责?如何使对象解耦,以支持低耦合并提高复用性?11/25/202329解决方案将职责分配给中介对象,使其作为其他构件或服务之间的媒介,以避免它们之间的直接耦合11/25/202330例子TaxCalculatorAdapterPersistentStorages:Sale:TaxMasterAdaptertaxes:=getTaxes(s)t:=getTotal()theadapteractsasalevelofindirectiontoexternalsystems<<System>>:TaxMasterTCPsocketcommunicationxxx...11/25/202331优点组件之间的低耦合11/25/2023322.4防止变异(ProtectedVariations)问题如何设计对象,子系统和系统,使其内部的变化或不稳定性不会对其它元素造成不良影响11/25/202334解决方案识别预计变化或不稳定之处,分配职责用以在这些变化之外创建稳定接口11/25/202335例子外部税金计算器问题11/25/202336讨论PV时非常重要和基本的软件设计原则。许多软件或架构设计技巧都是防止变异的特例Dataencapsulation,interfaces,polymorphism,indirection…Data-drivendesignsSOA…11/25/202337禁忌如果需要灵活性和对变化的预防,那么就应用

PV如果预测将来验证或者预测“复用”的可能性并不确定,则需要有克制和批评的态度11/25/202338初学者倾向于脆弱的设计而中等程度的开发者则倾向于过度想象的,灵活的,一般化的设计专家开发者理智地进行选择11/25/202339优点易于增加新变化所需的扩展可以引入新的实现而无需影响客户低耦合能够降低变化的成本或影响11/25/2023403.Gang-of-Four模式Gang-of-Four模式DesignPatterns,作为一本非常著名的书,是由四位作者写的,因此

我们使用“Gang-of-Four”11/25/2023423.1适配器Adapter(GOF)问题如何解决不相容的接口问题,或者如何为具有不同接口的类似构件提供稳定的接口?11/25/202344解决方案通过中介适配器对象,将构件的原来的接口转换为其它接口多态模式就是该模式的例子11/25/202345TaxMasterAdaptergetTaxes(Sale):ListofTaxLineItemsGoodAsGoldTaxProAdaptergetTaxes(Sale):ListofTaxLineItems<<interface>>ITaxCalculatorAdaptergetTaxes(Sale):ListofTaxLineItemsAdaptersuseinterfacesandpolymorphismtoaddalevelofindirectiontovaryingAPIsinothercomponents.SAPAccountingAdapterpostReceivable(CreditPayment)postSale(Sale)...GreatNorthernAccountingAdapterpostReceivable(CreditPayment)postSale(Sale)...<<interface>>IAccountingAdapterpostReceivable(CreditPayment)postSale(Sale)...<<interface>>IInventoryAdapter...<<interface>>ICreditAuthorizationServiceAdapterrequestApproval(CreditPayment,TerminalID,MerchantID)...11/25/202346:Register:SAPAccountingAdapterpostSale(sale)makePayment()theAdapteradaptstointerfacesinothercomponents<<system>>:SAPSOAPoverHTTPxxx...IAccountingAdapterUMLnotationtoindicatesomethingimplementsaparticularinterface11/25/202347Adapter

模式的应用是对GRASP构造块的特殊化

(polymorphism,indirectionandprotectedvariations)可以找到数百种模式的说明理解本质能够使我们摒弃太多细节11/25/202348两个问题命名习惯:将模式名字放在类型中设计中发现的“分析”:领域模型11/25/2023493.2工厂Factory(GoF)问题在适配器模式中,对外部服务有不同的接口,那么是谁创建了这些适配器,并且如何决定创建哪种类的适配器当有特殊考虑(例如存在复杂创建逻辑,为了改良内聚而分离创建职责等)时,应该由谁来负责创建对象?11/25/202351解决方案创建称为工厂的纯虚构对象来处理这些创建职责11/25/202352ServicesFactoryaccountingAdapter:IAccountingAdapterinventoryAdapter:IInventoryAdaptertaxCalculatorAdapter:ITaxCalculatorAdaptergetAccountingAdapter():IAccountingAdaptergetInventoryAdapter():IInventoryAdaptergetTaxCalculatorAdapter():ITaxCalculatorAdapter...notethatthefactorymethodsreturnobjectstypedtoaninterfaceratherthanaclass,sothatthefactorycanreturnanyimplementationoftheinterface{

if(taxCalculatorAdapter==null){//areflectiveordata-drivenapproachtofindingtherightclass:readitfroman//externalproperty

StringclassName=System.getProperty("");

taxCalculatorAdapter=(ITaxCalculatorAdapter)Class.forName(className).newInstance();}

returntaxCalculatorAdapter;}ItmaylessentheneedforinteractiondiagramData-drivendesign11/25/202353优点分离复杂的创建职责,并将其分配给内聚的帮助者对象隐藏潜在的复杂创建逻辑允许引入提高性能的内存管理策略,例如对象缓存或再生11/25/2023543.3单实例类Singleton问题谁来创建工厂自身?如何访问工厂?将实例作为一个参数进行传递对那些需要可见性的对象在初始化时赋予一个持久引用单实例模式:只允许类的一个实例:这是一个单实例。对象需要一个全局和唯一的访问点.11/25/202356解决方案对类定义静态方法用以返回单实例11/25/2023571ServicesFactoryinstance:ServicesFactoryaccountingAdapter:IAccountingAdapterinventoryAdapter:IInventoryAdaptertaxCalculatorAdapter:ITaxCalculatorAdaptergetInstance():ServicesFactorygetAccountingAdapter():IAccountingAdaptergetInventoryAdapter():IInventoryAdaptergetTaxCalculatorAdapter():ITaxCalculatorAdapter...singletonstaticattributesingletonstaticmethod{//staticmethodpublicstaticsynchronizedServicesFactory

getInstance(){if(instance==null)

instance:=newServicesFactory()returninstance}}UMLnotation:inaclassbox,anunderlined

attributeormethodindicatesastatic(classlevel)member,ratherthananinstancememberUMLnotation:this'1'canoptionallybeusedtoindicatethatonlyoneinstancewillbecreated(asingleton)LazyinitializationCreationworkisavoided,iftheinstanceisneveractuallyaccessedThegetInstancelazyinitializationsometimescontainscomplexandconditionalcreationlogic11/25/202358开发人员通过类的静态方法getInstance

得到其唯一实例的全局可见性publicclassRegister{publicvoidinitialize(){…dosomework…//accessingthesingletonFactoryviathegetInstancecall

accountingAdapter=ServiceFactory.getInstance().getAccountingAdapter();…dosomework…}//othermtehods..}11/25/202359UMLnotation:Register<<Singleton>>:ServicesFactoryaa:=getAccountingAdapter()initialize()...aUMLstereotypecanindicatethatvisibilitytothisinstancewasachievedviatheSingletonpattern11/25/202360具有不同接口的外部服务问题的结论使用适配器,工厂和单实例类模式的结合,为具有不同接口的外部税金计算器,财务系统等提供防止变异:RegisteraccountingAdapter:SAPAccountingAdapterpostSale(sale)makePayment()<<System>>:SAPSOAPoverHTTPxxxIAccountingAdapter:Register<<singleton>>:ServicesFactoryaccountingAdapter:=

getAccountingAdapter():Storecreate()create()[instance==null]create():SAPAccountingAdapterIAccountingAdapter:Paymentcreate(cashTendered)11/25/2023613.4策略(Strategy)问题提供更为复杂的定价逻辑,例如商店在某天的折扣,老年人折扣等如何设计变化但相关的算法或政策?如何设计才能使这些算法或政策具有可变更的能力11/25/202363解决方案在单独的类中分别定义每种算法/政策/策略,并且使其具有共同接口11/25/202364例子PercentDiscountPricingStrategypercentage:floatgetTotal(s:Sale):MoneyAbsoluteDiscountOverThresholdPricingStrategydiscount:Moneythreshold:MoneygetTotal(s:Sale):Money<<interface>>ISalePricingStrategygetTotal(Sale):Money{

returns.getPreDiscountTotal()*percentage}???PricingStrategy......{pdt:=s.getPreDiscountTotal()if(pdt<threshold)

returnpdtelse

returnpdt-discount}11/25/202365:PercentDiscountPricingStrategyISalePricingStrategys:Sale*:st:=getSubtotal()t:=getTotal():SalesLineItem:SalesLineItemt:=getTotal(s)pdt:=getPreDiscountTotal(){t=pdt*percentage}notethattheSalesispassedtotheStrategysothatithasparametervisibilitytoitforfurthercollaboration11/25/202366语境对象需要其策略的属性可见性PercentDiscountPricingStrategypercentage:floatgetTotal(Sale):MoneyAbsoluteDiscountOverThresholdPricingStrategydiscount:Moneythreshold:MoneygetTotal(Sale):Money<<interface>>ISalePricingStrategygetTotal(Sale):MoneySaledate...getTotal()...1*SaleneedsattributevisibilitytoitsStrategypricingStrategygetTotal(){...returnpricingStrategy.getTotal(this)}11/25/202367使用工厂创建策略1PricingStrategyFactoryinstance:PricingStrategyFactorygetInstance():PricingStrategyFactorygetSalePricingStrategy():ISalePricingStrategygetSeniorPricingStrategy():ISalePricingStrategy...{

StringclassName=System.getProperty("");

strategy=(ISalePricingStrategy)Class.forName(className).newInstance();returnstrategy;}Becauseofthefrequentlychangingpricingpolicyre-createoneeachtime11/25/202368:Sale<<singleton>>:PricingStrategyFactoryps:=getSalePricingStrategy():RegistermakeNewSale()create()create(percent)ps:PercentDiscountPricingStrategyISalePricingStrategy11/25/202369读取和初始化百分比值如何确定百分比或绝对值折扣的数值?这些数据将保存于某种外部数据存储中以便修改哪个对象读取这些数据,并确保将其分配给相应的策略?StrategyFactory

从外部数据源中读取数字的方法通过对其变化电贺金花店进行分析后来确定11/25/2023703.5组合模式(CompositePattern)问题如何处理多个互相冲突的定价策略?老年人20%的折扣对于购物金额满400元的优先客户给与折15%的折扣在星期一,购物金额满500元的享受50元的折扣买一罐印度大吉岭茶,则所有购买物品都享受15%的折扣11/25/202372解决冲突的策略对顾客最有利或者对商场最有利定价策略可能与产品类型相关,也可能与客户类型相关,这意味着:StrategyFactory

必须知道客户和产品的类型如何能够像处理非组合(原子)对象一样,(多态地)处理一组对象或具有组合结构的对象呢?11/25/202373解决方案为复合和原子对象定义一个类,以使他们实现相同的接口11/25/202374PercentageDiscountPricingStrategypercentage:floatgetTotal(Sale):MoneyAbsoluteDiscountOverThresholdPricingStrategydiscount:Moneythreshold:MoneygetTotal(Sale):Money<<interface>>ISalePricingStrategygetTotal(Sale):Money{

returnsale.getPreDiscountTotal()*percentage}CompositePricingStrategyadd(ISalePricingStrategy)getTotal(Sale):Money{lowestTotal=INTEGER.MAXforeachISalePricingStrategy

stratinpricingStrategies{

total:=strat.getTotal(sale)

lowestTotal=min(total,lowestTotal)}returnlowestTotal}1..*CompositeBestForCustomerPricingStrategygetTotal(Sale):MoneyCompositeBestForStorePricingStrategygetTotal(Sale):MoneypricingStrategiesAllcompositesmaintainalistofcontainedstrategies.Therefore,defineacommonsuperclassCompositePricingStrategy

thatdefinesthislist(namedpricingStrategies).Saledate...getTotal()...1*pricingStrategy{...returnpricingStrategy.getTotal(this)}Theoutercompositeobjectcontainsalistofinnerobjectsandboththeouterandinnerobjectsimplementthesameinterface11/25/202375:CompositeBestForCustomerPricingStrategyISalePricingStrategys:Sale*:st:=getSubtotal()t:=getTotal():SalesLineItem:SalesLineItemt:=getTotal(s)theSaleobjecttreatsaCompositeStrategythatcontainsotherstrategiesjustlikeanyotherISalePricingStrategy*:x:=getTotal(s):SalesLineItem:ObjectISalePricingStrategyUMLnotation:thisisawaytoindicateobjectsthatimplementsomeinterface,whenwedon'twanttodeclarewhatthespecificimplementationclassesare{t=min(setofallx)}11/25/202376创建多个SalePricingStrategies什么时候创建这些策略呢?在情形中有三个地方可以将定价策略加入到符合对象中:目前商店定义的折扣,可以在销售对象创建时添加顾客类型的折扣,可以在POS机获取顾客类型时添加产品类型的折扣

(ifboughtDarjeelingtea,15%offtheoverallsale),可以在产品输入到销售中时添加11/25/202377:Sale<<singleton>>:PricingStrategyFactoryps:=getSalePricingStrategy():RegistermakeNewSale()create()create()ps:CompositeBestForCustomerPricingStrategyISalePricingStrategycreate(percent)s:PercentageDiscountPricingStrategyISalePricingStrategyadd(s)11/25/202378对于客户类型折扣的第二种情形UseCaseUC1:ProcessSale…扩展

(orAlternativeFlows):5b.Customersaystheyareeligibleforadiscount(e.g.,employee,preferredcustomer)1.Cashiersignalsdiscountrequest2.CashierentersCustomeridentification3.Systempresentsdiscounttotal,basedondiscountrules11/25/202379s:Sale:RegisterenterCustomerForDiscount(custID)byControllerbyExpertandIDstoObjects:Storec:=getCustomer(custID)enterCustomerForDiscount(c:Customer)continuedinanotherdiagrambyExpert11/25/202380s:Sale<<singleton>>:PricingStrategyFactoryaddCustomerPricingStrategy(s)ps:CompositeBestForCustomerPricingStrategyISalePricingStrategycreate(pct)s:PercentageDiscountPricingStrategyISalePricingStrategyadd(s)byExpertenterCustomerForDiscount(c:Customer)originatesinanotherdiagramc:=getCustomer()byFactoryandHighCohesionbyExpertps:=getPricingStrategy()pct:=getCustomerPercentage(c)byHighCohesionbyFactoryandCompositePassAggregateObjectasParameter11/25/202381两个通用实践IDs到对象Acommonpracticeinobjectdesign-totransformkeysandIDsforthingsintotrueobjectsTransformthecustomerIDintoaCustomerobject将聚集对象作为参数addCustomerPricingStrategy(s:Sale)messagewepassaSaletothefactory,andthenthefactoryturnsaroundandasksfortheCustomerandPricingStrategyfromtheSale11/25/2023823.6外观(Façade)问题可插拔的业务规则创建新销售时,可能要识别该销售是否以礼券方式进行支付。商店可能会规定如果使用礼券只可以购买一件商品。如果销售使用礼券支付,在对该顾客找零时,除了礼券之外所有其它支付类型的找零都应该置为无效。例如,如果收银员请求现金找零或更新顾客在其商店帐户上的积分时,这些请求都应该判断为无效….如何设计一个软件对目前的软件组件影响最小呢?11/25/202384解决方案定义对子系统的单一的接触点-用一个外观对象包装子系统。外观对象提供了一个唯一的统一接口,它负责与子系统的组件进行协作11/25/202385子系统的外观对象被称为POSRuleEngineFacade.设计者决定在所有定义了可插拔规则的方法的开始之处调用这一外观publicclassSale{publicvoidmakeLineItem(ProductSpecificationspec,intquantity){SalesLineItem

sli=newSalesLineItem(spec,quantity);//calltotheFaçadeif(POSRuleEngineFacade.getInstance().isInvalid(sli,this))return;linItems.add(sli);}//…}//endofclass11/25/202386Domain+Sale+Register...POSRuleEngine<<interface>>-IRule...-Rule1...-Rule2......packagenamemaybeshowninthetabvisibilityofthepackageelement(tooutsidethepackage)canbeshownbyprecedingtheelementnamewithavisibilitysymbol+POSRuleEngineFacadeinstance:RuleEngineFacadegetInstance():RuleEngineFacadeisInvalid(SalesLineItem,Sale)isInvalid(Payment,Sale)...*111/25/202387外观一般通过单实例模式来访问外观

vs.适配器适配器对外部系统的访问进行了封装,尽管它是一种外观,它强调的是对各种接口的兼容性11/25/2023883.7观察者/发布-订阅/委派事件模型问题添加当总价变化时,GUI窗口能够更新其显示的能力Goal:Whenthetotalofthesalechanges,refreshthedisplaywiththenewvalueSaletotal...setTotal(newTotal)...Solution1:WhentheSalechangesthetotal,theSaleobjectsendsamessagetoawindow,askingittorefreshitsdisplayViolationofModel-ViewSeparationPrinciple11/25/202390解决方案定义一个“订阅”or“聆听者”接口.订阅者实现该接口。发布者可以动态的注册对事件感兴趣的订阅者,并在事件发生时,通知它们。11/25/202391<<interface>>PropertyListeneronPropertyEvent(source,name,value)SaleFrame1onPropertyEvent(source,name,value)initialize(Salesale)...javax.swing.JFrame...setTitle()setVisible()...{if(name.equals("sale.total"))

saleTextField.setText(value.toString());}SaleaddPropertyListener(PropertyListener

lis)publishPropertyEvent(name,value)setTotal(MoneynewTotal)...*propertyListeners{

total=newTotal;

publishPropertyEvent("sale.total",total);}{

propertyListeners.add(lis);}{

foreachPropertyListenerplinpropertyListeners

pl.onPropertyEvent(this,name,value);}{

sale.addPropertyListener(this)...}11/25/202392s:Salesf:SaleFrame1initialize(s:Sale)addPropertyListener(sf)PropertyListenerpropertylisteners:Objectadd(sf)PropertyListenerUMLnotation:Recallthatthereisnosuchthingasaninstanceofaninterface.Therefore,wecangeneralize(orbevague)andsimplyindicatetheinstancesastypeObject,whichisassumedtobethesuperclassofallclasses.Thisapproachcanbeusedevenifthelanguage(suchasC++)doesnotliterallydefinearootObjectsuperclass.11/25/202393s:SalesetTotal(total)*:onPropertyE

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论