1、设计模式,Design Patterns,设计模式编目(Catalog),2,案例研究:设计一个文本编辑器 -支持多种视感标准,3,设计问题,可移植性的问题:考虑Lexi在如下系统的视感(look-and-feel) Windows Motif PM (Presentation Manager) Max OS X KDE 移植的一大障碍是不同视感标准之间的差异性,4,设计目标,使Lexi符合多个已存在的视感标准,并且在新标准出现时要能很容易地增加对新标准的支持 能支持最大限度的灵活性:运行时刻可以改变Lexi的外观和感觉,5,对象创建的抽象(Abstracting Object Creation),需要2个窗口组件(Widgets)图元集合来实现多个视感标准 抽象的(abstract) 由抽象Glyph子类构成 如:滚动条(ScrollBar)/按钮(Button)、 具体的(concrete) 实现不同视感标准的具体的子类 如:Motif滚动条(MotifScrollBar)、Win滚动条(WinScrollBar)、Mac滚动条(MacScrollBar)、Motif按钮(Moti
2、fButton)、 ,6,对象创建的抽象(Abstracting Object Creation),Lexi必须区分不同视感风格的窗口组件图元之间的差异 例如:当Lexi需要在界面上放一个按钮时,它必须实例化一个有正确按钮风格的Glyph子类(MotifButton、PMButton或MacButton等) Lexi需要一种方法来确定创建合适窗口组件所需的视感标准 必须避免显式的构造器调用 必须能够很容易地替换整个窗口组件集合 可以通过抽象对象创建过程(abstracting the process of object creation)来达到上述两个要求,7,对象工厂,传统方法:使用下面的C+代码来创建一个Motif滚动条图元实例 ScrollBar* sb = new MotifScrollBar; 要使Lexi的视感依赖性最小的话,上面这种代码要尽量避免 使用工厂方法 ScollBar* sb = guiFactory-CreateScrollBar(); guiFactory是MotifFactory类的实例,8,GUIFactory类层次,9,GUIFactory类层次,GU
3、IFactory是定义了创建窗口组件图元公共接口的抽象类,它包含了用以实例化不同窗口组件图元的像CreateScrollBar和CreateButton这样的操作。 GuiFactory的子类实现这些操作,并返回像MotifScrollBar和PMButton这样实现特定视感的图元。,10,Lexi的抽象产品类和具体子类,11,抽象类,具体类,建立工厂,工厂创造了产品对象 如果视感在编译时刻就知道了,那么guiFactory能够在程序开始的时候以一个新的工厂实例简单赋值来初始化: GUIFactory* guiFactory = new MotifFactory; 如果用户能通过程序启动时候的字符串来指定视感,那么创建工厂的代码可能是:,12,String LandF = appProps.getProperty(“LandF“); GUIFactory guiFactory; if( LandF.equals(“Motif“) ) guiFactory = new MotifFactory(); .,Abstract Factory(抽象工厂)模式,该模式描述了怎样在不直接实例化类的
4、情况下创建一系列相关的产品对象 适用于产品对象的数目和种类不变,而具体产品系列之间存在不同的情况 通过实例化一个特定的具体工厂对象来选择产品系列,并且以后一直使用该工厂生产产品对象,13,Abstract Factory(抽象工厂) 模式的描述,14,模式名和分类(Name),模式名:Abstract Factory(抽象工厂) 分类:对象创建型模式,15,意图(Intent),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。,16,别名(Also Known As),Kit,17,动机(Motivation),考虑一个支持多种视感(look-and-feel)标准的用户界面工具包,例如Motif和Presentation Manager (PM)。 不同的视感风格为诸如滚动条、窗口和按钮等用户界面“窗口组件”定义不同的外观和行为。 为保证视感风格标准间的可移植性,一个应用不应该为一个特定的视感外观硬编码它的窗口组件。 在整个应用中实例化特定视感风格的窗口组件类将使得以后很难改变视感风格。,18,动机(Motivation),19,L2,动机(Motivation)
5、,每一种视感标准都对应于一个具体的WidgetFactory子类。每一子类实现那些用于创建合适视感风格的窗口组件的操作。 客户仅与抽象类定义的接口交互,而不使用特定的具体类的接口,20,适用性(Applicability),以下情形适用Abstract Factory模式: 一个系统要独立于它的产品的创建、组合和表示时 一个系统要由多个产品系列中的一个来配置时 当你要强调一系列相关的产品对象的设计以便进行联合使用时 当你提供一个产品类库,而只想显示它们的接口而不是实现时,21,结构(Structure),22,参与者(Participants),AbstractFactory (WidgetFactory) 声明一个创建抽象产品对象的操作接口 ConcreteFactory (MotifWidgetFactory, MWidgetFactory) 实现创建具体产品对象的操作 AbstractProduct (Windows, ScrollBar) 为一类产品对象声明一个接口 ConcreteProduct (MotifWindow, MotifScrollBar) 定义一个将被相应的具
6、体工厂创建的产品对象。 实现AbstractProduct接口。,23,参与者(Participants),Client 仅使用由AbstractFactory和AbstractProduct类声明的接口。,24,协作(Collaborations),通常在运行时刻创建一个ConcreteFactroy类的实例。这一具体的工厂创建具有特定实现的产品对象。为创建不同的产品对象,客户应使用不同的具体工厂。 AbstractFactory将产品对象的创建延迟到它的ConcreteFactory子类。,25,效果(Consequences),AbstractFactory模式有下面的一些优点和缺点: 它分离了具体的类 一个工厂封装创建产品对象的责任和过程,它将客户与类的实现分离。客户通过它们的抽象接口操纵实例。产品的类名也在具体工厂的实现中被分离;它们不出现在客户代码中。 它使得易于交换产品系列 一个具体工厂类在一个应用中仅出现一次即在它初始化的时候。这使得改变一个应用的具体工厂变得很容易。它只需改变具体的工厂即可使用不同的产品配置,这是因为一个抽象工厂创建了一个完整的产品系列,所以整个产品系
7、列会立刻改变。,26,效果(Consequences),它有利于产品的一致性 当一个系列中的产品对象被设计成一起工作时,一个应用一次只能使用同一个系列中的对象,这一点很重要。而AbstractFactory很容易实现这一点。 难以支持新种类的产品 难以扩展抽象工厂以生产新种类的产品。这是因为AbstractFactory接口确定了可以被创建的产品集合。支持新种类的产品就需要扩展该工厂接口,这将涉及AbstractFactory类及其所有子类的改变。,27,实现(Implementation),实现Abstract Factor模式的一些有用技术: 略(见书本P59(中文版) 将工厂作为单件(Singleton) 创建产品 定义可扩展的工厂,28,代码示例(Sample Code),迷宫的例子 略(见书本P61(中文版),29,已知应用(Known Uses),略(见书本P63 (中文版),30,相关模式(Related Patterns),Factory Method(工厂方法模式) Prototype(原型模式) Singleton(单件模式),31,Factory Method(工
8、厂方法) 模式的描述,32,模式名和分类(Name),模式名:Factory Method(工厂方法) 分类:类创建型模式 注: 创建型模式抽象了实例化过程 类创建型模式使用继承改变被实例化的类 对象创建型模式将实例化委托给另一个对象,33,意图(Intent),定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method使一个类的实例化延迟到其子类。,34,别名(Also Known As),虚构造器( Virtual Constructor),35,动机(Motivation),考虑这样一个应用框架,它可以向用户显示多个文档。在这个框架中,两个主要的抽象是类Application和Document。这两个类都是抽象的,客户必须通过它们的子类来做与具体应用相关的实现。 因为被实例化的特定Document子类是与特定应用相关的,所以Application类不可能预测到哪个Document子类将被实例化 Application类仅知道一个新的文档何时应被创建,而不知道哪一种Document将被创建。这就产生了一个尴尬的局面:框架必须实例化类,但是它只知道不能被实例
9、化的抽象类,36,动机(Motivation),Factory Method模式提供了一个解决办案。它封装了哪一个Document子类将被创建的信息并将这些信息从该框架中分离出来 Application的子类重定义Application的抽象操作CreateDocument以返回适当的Document子类对象 一旦一个Application子类实例化以后,它就可以实例化与应用相关的文档,而无需知道这些文档的类 我们称CreateDocument是一个工厂方法(factory method),因为它负责“生产”一个对象,37,L2,动机(Motivation),38,适用性(Applicability),以下情形适用Factory Method模式: 当一个类不知道它所必须创建的对象的类的时候 当一个类希望由它的子类来指定它所创建的对象的时候 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将这一信息(哪个子类受委托)局部化的时候,39,结构(Structure),40,参与者(Participants),Product(Document) 定义工厂方法所创建的对象的接口 ConcreteProduct(MyDocument) 实现Product接口 Creator(Application) 声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的ConcreteProduct对象。 可以调用工厂方法以创建一个Product对象。 ConcreteCreator(MyApplication) 重定义工厂方法以返回一个ConcreteProduct实例。,41,协作(Collaborations),Creator依赖于它的子类来定义工厂方法,所以它返回一个适当的ConcreteProduct实例,42,效果(Consequences),Factory Method模式有下面的一些优点和缺点: 不再将与特定应用有关的类绑定到你的代码中。代码仅处理Product接口;因此它可以与用户定义的任何ConcreteProduct类一起使用。 潜在缺点在于客户可能仅仅为了创建一个特定的ConcreteProduct对象,就不得不创建
《软件设计-理论课04》由会员luoxia****01802分享,可在线阅读,更多相关《软件设计-理论课04》请在金锄头文库上搜索。