版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第六章 结构型设计模式返回目录l目录l【6.1】 适配器模式 l6.2 装饰模式 实验实验l6.3 桥接模式 实验实验l【6.4】 享元模式享元模式l6.5 外观模式 实验实验l【6.6】 代理模式代理模式l【6.7】 组合模式组合模式返回目录6.1 适配器(Adapter)模式一.适配器模式的由来 二.适配器模式的意图和适用性三.适配器模式结构及参与者 四.应用举例五.效果分析返回目录6.1.1 适配器模式的由来l Adapter模式解决的问题在生活中经常会遇到:比如我们有一个team为外界提供S类服务,但是我们team里面没有能够完成此项任务的member,然后我们得知有A可以完成这项服务
2、。teamSAs返回目录6.1.1 适配器模式的由来-同学们的解决方案teamSAsTeam() a=New AS( ) a.s();把A直接招安到我们team为我们工作,提供S服务的时候让A去办就是了; Team t=new team();t.s()使用方法思考:该方法的缺陷?能不能不修改team的代码返回目录6.1.1 适配器模式的由来 -改进思路teamSAsS( ) adapterA a;adapter() a=New A()S( ) a.s();?问题:team与adapter如何连接?返回目录6.1.1 适配器模式的由来 -改进思路teamSAsS( ) adapterA a;ad
3、apter() a=New AS( ) a.s();返回目录6.1.1 适配器模式的由来适配器模式的由来 -适配器的用途,软件项目的复用适配器的用途,软件项目的复用实际上在软件系统设计和开发中,这种问题会经常遇到:我们为了完成某项工作购买了一个第三方的库来加快开发。这就带来了一个问题:我们在应用程序中已经设计好了功能接口,与这个第三方提供的接口不一致,为了使得这些接口不兼容的类(不能在一起工作)可以在一起工作,Adapter模式提供了将一个类(第三方库)的接口转化为客户(购买使用者)希望的接口。返回目录6.1.1 适配器模式的由来-新系统通过适配器复用旧系统新系统旧系统适配器返回目录6.1.1
4、 适配器模式的由来-新系统通过适配器复用旧系统l将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。返回目录6.1.2 适配器模式意图和适用性 -适配器的其他用途适配器的其他用途l 你想使用一个已经存在的类,而它的接口不符合你的要求。l 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。l (仅适用于对象Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。l 适配器模式分为类模式适配器和对象模式适配器
5、。返回目录Adapter Pattern(类模式)结构图 Adapter Pattern(对象模式)结构图 6.1.3 适配器模式结构及参与者返回目录l 类适配器和对象适配器有不同的权衡。类适配器用一个具体的adapter类对adaptee和target进行匹配。结果是当我们想要匹配一个类及以及所有它的子类时,类adapter将不能胜任工作。使得adapter可以重定义adaptee的部分行为,因为adapter是adaptee的一个子类。仅仅引入了一个对象,并不需要额外的指针以间接得到adaptee。l 对象适配器则允许一个adapter与多个adaptee(即adaptee本身以及它的所有
6、子类)同时工作。Adapter也可以一次给所有的adaptee添加功能。使得重定义adaptee的行为比较困难。这就需要生成adaptee的子类并且使得adapter引用这个子类而不是引用adapter本身。6.1.3 适配器模式意图和适用性返回目录class Target public: virtual void Request(); ;class Adaptee public: void SpecificRequest(); ;class Adapter:public Target,private Adaptee/同时继承Target和Adapatee public: void Reque
7、st(); ; void Adapter:Request() this-SpecificRequest(); /通过继承实现Adaptee的方法SpecificRequest () 代码说明:类模式6.1.4 应用举例返回目录class Target public: virtual void Request(); ; class Adaptee public: void SpecificRequest(); ; class Adapter:public Target public: Adapter(Adaptee* ade); /产生一个Adaptee对象Adapter(); void Req
8、uest(); private: Adaptee* _ade; ; Adapter:Adapter(Adaptee* ade) this-_ade = ade; /传递Adaptee对象到Adapter void Adapter:Request() _ade-SpecificRequest(); /适配器调用SpecificRequest()方法 int main(int argc,char* argv) Adaptee* ade = new Adaptee; Target* adt = new Adapter(ade); adt-Request(); /实现Target的对象访问Specif
9、icRequest()方法return 0; 代码说明:对象模式返回目录6.1.5 效果分析l优点:方便设计者可以自由定义接口,而不用担心匹配的问题。l缺点:属于静态结构 ,由于只能单继承,所以不适用于多种不同的源适配到同一个目标。返回目录6.2 装饰(Decorator)模式【实验】一.装饰模式的由来二.装饰模式意图及适用性三.装饰模式结构和参与者 四.应用举例五.效果分析返回目录6.2.1 装饰模式的由来aA方法1方法2方法3思考:如何为A类添加新的方法?返回目录6.2.1 装饰模式的由来A方法1方法2方法3思考:如何为A类添加新的方法?思考:此方法的缺陷sonofA方法4返回目录6.2.
10、1 装饰模式的由来A方法1方法2方法3思考:如何为A类添加新的方法?方法4newA*aA方法1方法2方法3方法1()( aA.方法1(); 返回目录6.2.1 装饰模式的由来A方法1方法2方法3思考:如何扩充A类方法3?返回目录6.2.1 装饰模式的由来A方法1方法2方法3思考:如何扩充A类方法3?方法1:继承返回目录6.2.1 装饰模式的由来A方法1方法2方法3思考:如何扩充A类方法3?方法2:组合interfaceofA方法1方法2方法3decoratorofA方法3*aA方法3()( aA.方法3(); 扩展部分;新成员返回目录6.2.1 装饰模式的由来l装饰模式动态地给一个对象添加额外
11、的职责。不论一幅画有没有画框都可以挂在墙上,画就是被装饰者。但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。而玻璃画框就是装饰。返回目录6.2.1 装饰模式的由来l Decorator模式的提出:l 在OO设计和开发过程,可能会经常遇到以下的情况:我们需要为一个已经定义好的类添加新的职责(操作),通常的情况我们会给定一个新类继承继承自定义好的类,这样会带来一个问题。通过继承的方式解决这样的情况还带来了系统的复杂性,因为继承的深度会变得很深。 l 而Decorator提供了一种给类增加职责的方法,不是通过继承实现的
12、,而是通过组合。返回目录6.2.2 Decorator模式意图和适用性l动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。返回目录6.2.2 Decorator模式意图和适用性以下情况使用Decorator模式在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况时因为类定义被隐藏,或类定义不能用于生成子类。返回目录Decorator Pattern结构图 6.2.3 Decorator模式结构和参
13、与者返回目录l通过结构图中的ConcreteComponent和Decorator有一个,就可以利用OO中的思想来实现只要是Component型别的对象都可以提供修饰操作的类,这种情况下你就算新建了100个 Component型别的类ConcreteComponent,也都可以由Decorator一个类搞定。这也正是Decorator模式的关键和威力所在了。 6.2.3 Decorator模式结构和参与者返回目录class Component /定义一个对象接口,可以给这些对象动态地添加职责 public: virtual void Operation(); protected: Compon
14、ent(); ; class ConcreteComponent:public Component/定义一个对象,可以给这个对象添加一些职责 public: void Operation(); ; class Decorator:public Component/ 维持一个指向Component对象的指针,并定义一个与Component一致的接口 public: Decorator(Component* com); protected: Component* _com; ; class ConcreteDecorator:public Decorator /向组件添加职责 public: Co
15、ncreteDecorator(Component* com); ConcreteDecorator(); void Operation(); void AddedBehavior(); ; 6.2.4 代码说明返回目录Decorator:Decorator(Component* com) this-_com = com; Decorator:Decorator() delete _com; void ConcreteDecorator:Operation() _com-Operation(); this-AddedBehavior(); 6.2.4 代码说明返回目录6.2.4 代码说明int
16、 main(int argc,char* argv) /Decorator将请求转发给它的Component对象,并有可能在转发前后执行一些附加的动作Component* com = new ConcreteComponent();Decorator* dec = new ConcreteDecorator(com); dec-Operation(); /隐藏了ConcreteComponent和ConcreteDecoratordelete dec; return 0; 返回目录6.2.5 效果分析l 装饰模式的优缺点:使用Decorator模式可以很容易地向对象添加职责的方式。可以用添加和
17、分离的方法,用装饰在运行时添加和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类,这会产生很多新的类,并会增加系统的复杂度。使用Decorator模式可以很容易地重复添加一个特性,而两次继承特性类则极容易出错。 返回目录6.2.5 效果分析l 装饰模式的优缺点:避免在层次结构高层的类有太多的特征:lDecorator模式下,你可以定义一个简单的类,并用Decorator类给他逐渐地添加功能,这样可以从简单的部件组合出复杂的功能。具有低依赖性和低复杂性。有许多小对象l采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,尽管对于了解这些系统的人来说,很容易进行定
18、制,但是很难学习这些系统,排错也很困难。返回目录6.3 桥接(Bridge)模式【实验】一.桥接模式的由来 二.桥接模式的意图和适用性三.桥接模式结构及参与者 四.应用举例五.效果分析返回目录6.3.1 桥接模式的由来MediumMilkcoffeeMediumoriginalcoffeepourCoffeecoffeepourCoffeeSuperSizeMilkcoffeeSuperSizeoriginalcoffeepourCoffeePouroneservingmilk();for (int i = 0; i 2; i+)pouroneservingCoffee();思考:加入咖啡可以
19、添加橙汁、苹果汁,怎么办?增加小杯怎么办?中杯牛奶咖啡中杯原味咖啡大杯牛奶咖啡大杯原味咖啡返回目录6.3.1 桥接模式的由来MediumMilkcoffeeMediumoriginalcoffeepourCoffeecoffeepourCoffeeSuperSizeMilkcoffeeSuperSizeoriginalcoffeepourCoffeePouroneservingmilk();for (int i = 0; i 2; i+)pouroneservingCoffee();抽象与行为l其中抽象为:中杯和大杯;l行为为:加奶 不加奶(如加橙汁 加苹果汁). 返回目录coffeecoff
20、eeImpMediumcoffeeSuperSizecoffeecoffeeImppourCoffeefor (int i = 0; i 2; i+)coffeeImp.pourCoffeeImp();MilkCoffeeImppourCoffeeImp()CoffeeImpSingletonl/拿出牛奶CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp();/中杯加奶MediumCoffee mediumCoffee = new MediumCoffee();mediumCoffee
21、.pourCoffee();/大杯加奶SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();superSizeCoffee.pourCoffee();private static CoffeeImp coffeeImpsetCoffeeImp()this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp();public void pourCoffeeImp() System.out.println(加了美味的牛奶);返回目录6.3.1 桥接模式的由来l 如果一个抽象类或接口有多个具体实现(子类
22、、concrete subclass),这些子类之中有内容概念上重叠那么需要我们把抽象共同部分和行为共同部分各自独立开来,原来是准备放在一个接口里,现在需要设计两个接口:抽象接口和行为接口,分别放置抽象和行为.l 但是,我们注意到:上面四个子类中有概念重叠,可从另外一个角度进行考虑,这四个类实际是两个角色的组合:抽象 和行为,其中抽象为:中杯和大杯;行为为:加奶 不加奶(如加橙汁 加苹果汁). l 我们从分离抽象和行为的角度,使用Bridge模式来实现。 返回目录l问题说明l 一个典型的应用例子就是相同模块的跨平台使用设计模块A和B;希望模块A和B能应用在X操作系统上,让A和B继承X操作系统的
23、接口;希望模块A和B能应用在Y操作系统上,让A和B继承Y操作系统的接口,以此类推问题:模块A和B缺乏复用性。解决:抽象出统一的操作系统类的接口连接模块A和B的平台无关接口,通过桥接两个抽象模块来消除模块间的继承耦合,提高复用性。6.3.1 桥接模式的由来返回目录6.3.1 桥接模式的由来ABABX操作系统XD1()XD2()Y操作系统YD1()YD2()返回目录6.3.1 桥接模式的由来X操作系统XD1()XD2()Y操作系统YD1()YD2()AF() xd1(); xd2();AF() yd1(); yd2();返回目录6.3.1 桥接模式的由来X操作系统XD1()XD2()AF() AI
24、mp.d1(); AImp.d2();AImpd1();d2();xAImpd1();d2();D1() xd1();yAImpd1();d2();D1() yd1();*AImpy操作系统yD1()yD2()AF() AImp.d1(); AImp.d2();*AImp返回目录问题说明6.3.1 桥接模式的由来返回目录6.3.2 桥接模式的意图和适用性l 传统地,当一个抽象可能有多个实现时,通常用继承来协调它们。抽象类定义该抽象的接口,而具体的子类则用不同的方式加以实现。但是此方法有时不够灵活。继承机制将抽象部分与它的实现部分固定在一起,使得难以对抽象部分和实现部分独立地进行修改。扩充和重用
25、。l 桥接模式的作用就是将抽象部分与实际部分分离,使它可以独立的变化。 返回目录6.3.2 桥接模式的意图和适用性以下一些情况使用Bridge模式:l你不希望在抽象和它的实现部分之间有一个固定的绑定关系。l(C+)你想对客户完全隐藏抽象的实现部分。在C+中,类的表示在类接口中是可见的。返回目录6.2.3 桥接模式结构及参与者返回目录6.2.3 桥接模式结构及参与者l 其中,Abstraction定义抽象类的接口,它维护了一个指向Implementor类型对象的指针;l RefinedAbstraction扩充由Abstraction定义的接口;l Implementor定义实现类的接口,该接口
26、不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于和谐基本操作的较高层次操作;l ConcreteImplementor实现Implementor接口并定义它的具体实现;Abstraction将client的请求转发给它的Implementor对象。 返回目录6.2.4 应用举例l以上面提到的咖啡 为例. 我们原来打算只设计一个接口(抽象类),使用Bridge模式后,我们需要将抽象和行为分开,加奶和不加奶属于行为,我们将它们抽象成一个专门的行为接口. l先看看抽象部分的接口代码:
27、public abstract class Coffee CoffeeImp coffeeImp; public void setCoffeeImp() this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp(); public CoffeeImp getCoffeeImp() return this.CoffeeImp; public abstract void pourCoffee();l其中CoffeeImp 是加不加奶的行为接口,看其代码如下:public abstract class CoffeeImp public abstract v
28、oid pourCoffeeImp();返回目录l现在我们有了两个抽象类,下面我们分别对其进行继承,实现concrete class:l/中杯public class MediumCoffee extends Coffee public MediumCoffee() setCoffeeImp(); public void pourCoffee() CoffeeImp coffeeImp = this.getCoffeeImp(); /我们以重复次数来说明是冲中杯还是大杯 ,重复2次是中杯 for (int i = 0; i 2; i+) coffeeImp.pourCoffeeImp(); /
29、大杯public class SuperSizeCoffee extends Coffee public SuperSizeCoffee() setCoffeeImp(); public void pourCoffee() CoffeeImp coffeeImp = this.getCoffeeImp(); /我们以重复次数来说明是冲中杯还是大杯 ,重复5次是大杯 for (int i = 0; i 5; i+) coffeeImp.pourCoffeeImp(); 返回目录l 上面分别是中杯和大杯的具体实现.下面再对行为CoffeeImp进行继承:l /加奶public class Milk
30、CoffeeImp extends CoffeeImp MilkCoffeeImp() public void pourCoffeeImp() System.out.println(加了美味的牛奶); /不加奶public class FragrantCoffeeImp extends CoffeeImp FragrantCoffeeImp() public void pourCoffeeImp() System.out.println(什么也没加,清香); Bridge模式模式的基本框架我们已经搭好了,别忘记定义中还有一句:动态结合,我们现在可以喝到至少四种咖啡:1.中杯加奶2.中杯不加奶3
31、.大杯加奶4.大杯不加奶返回目录l看看是如何动态结合的,在使用之前,我们做个准备工作,设计一个单态类(Singleton)用来hold当前的CoffeeImp:lpublic class CoffeeImpSingleton private static CoffeeImp coffeeImp; public CoffeeImpSingleton(CoffeeImp coffeeImpIn) this.coffeeImp = coffeeImpIn; public static CoffeeImp getTheCoffeeImp() return coffeeImp; 看看中杯加奶 和大杯加奶
32、 是怎么出来的:l/拿出牛奶CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp();/中杯加奶MediumCoffee mediumCoffee = new MediumCoffee();mediumCoffee.pourCoffee();/大杯加奶SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();superSizeCoffee.pourCoffee();返回目录l Bridge模式有以下一些优点:l 1) 分离接口及其实现
33、部分 一个实现未必不变地绑定在一个接口上。抽象类的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现。l 将Abstraction与Implementor分离有助于降低对实现部分编译时刻的依赖性,当改变一个实现类时,并不需要重新编译 Abstraction类和它的客户程序。为了保证一个类库的不同版本之间的二进制兼容性,一定要有这个性质。l 另外,接口与实现分离有助于分层,从而产生更好的结构化系统,系统的高层部分仅需知道Abstraction和Implementor即可。6.3.5 效果分析返回目录6.3.5 效果分析l2) 提高可扩充性 你可以独立地对Abstraction和I
34、mplementor层次结构进行扩充。l3) 实现细节对客户透明 你可以对客户隐藏实现细节,例如共享 Implementor对象以及相l应的引用计数机制(如果有的话)。返回目录6.4 享元(Flyweight)模式一、享元模式的由来二、享元模式的意图及适用性三、享元模式的结构及参与者四、应用举例五、效果分析返回目录6.4.1 享元模式的由来l 当大量从数据源中读取字符串,其中肯定有重复的,那么我们使用Flyweight模式可以提高内存效率,以唱片CD为例 l 每个CD有三个字段:1.出片日期(year)2.歌唱者姓名等信息(artist)3.唱片曲目 (title)l 其中,歌唱者姓名有可能重
35、复,也就是说,可能有同一个演唱者的多个不同时期 不同曲目的CD.共享数据库是怎么做的?出片日期出片日期(year)歌唱者姓名等信息歌唱者姓名等信息(artist)唱片曲目唱片曲目 (title)返回目录6.4.1 享元模式的由来 -解决冗余(重复)思路l我们将歌唱者姓名作为可共享的ConcreteFlyweight.其他两个字段作为UnsharedConcreteFlyweight.l当你有几千张甚至更多CD时,Flyweight模式将节省更多空间,共享的flyweight越多,空间节省也就越大.返回目录6.4.2 享元模式的意图和适用性l 避免大量拥有相同内容的小类的开销(如耗费内存),使大
36、家共享一个类(元类). l 一个应用程序使用了大量的对象, l 完全有余使用了大量的对象,造成了很大的存储开销。 返回目录6.4.2 享元模式的意图和适用性Flyweight返回目录6.4.2 享元模式的意图和适用性出片出片日期日期(year)歌唱者姓名歌唱者姓名等信息等信息(artist)唱片唱片曲目曲目 (title)1990刘德华.Title11991张学友Title21992张学友Title31993刘德华Title41990郭富城Title51991郭富城Title61993刘德华Title7刘德华刘德华张学友张学友郭富城郭富城123出片日出片日期期(year)歌唱者歌唱者姓名等姓名
37、等信息信息(artist)唱片曲唱片曲目目 (title)19901Title119912Title219922Title319931Title419903Title519913Title619931Title7key返回目录6.4.2 享元模式的意图和适用性刘德华刘德华张学友张学友郭富城郭富城123出片日出片日期期(year)歌唱者歌唱者姓名等姓名等信息信息(artist)唱片曲唱片曲目目 (title)19901Title119912Title219922Title319931Title419903Title519913Title619931Title7key享元工厂 getFlyweig
38、ht(key) getFlyweight(“1”)返回目录Flyweight结构图如下所示:6.4.3 享元模式的结构及参与者返回目录6.4.3 享元模式的结构及参与者l Flyweight:描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。 l ConcreteFlyweight:实现flyweight接口,并为内部状态增加存储空间。ConcreteFlyweight对象必须是可以共享的,它所存储的状态必须是内部的。即:它必须独立于ConcreteFlyweight对象的场景. l Flyweight factory负责维护一个Flyweight池(存放内部状态),当客户
39、端请求一个共享Flyweight时,这个factory首先搜索池中是否已经有可适用的,如果有,factory只是简单返回送出这个对象,否则,创建一个新的对象,加入到池中,再返回送出这个对象.返回目录6.4.4代码分析:public class FlyweightFactory /Flyweight pool private Hashtable flyweights = new Hashtable(); Flyweight池 public Flyweight getFlyweight( Object key ) 通过对象key来访问 Flyweight flyweight = (Flyweigh
40、t) flyweights.get(key); if( flyweight = null ) /产生新的具体的享元对象 flyweight = new ConcreteFlyweight(); flyweights.put( key, flyweight ); return flyweight; /享元方法的具体实现:FlyweightFactory factory = new FlyweightFactory(); Flyweight fly1 = factory.getFlyweight( Fred ); Flyweight fly2 = factory.getFlyweight( Wil
41、ma );返回目录6.4.5 效果分析lFlyweight模式的核心就是把大量共享的对象收集在一起使用简单工厂模式进行管理,避免由于大量的小对象导致系统的内存过渡消耗 lFlyweight当重复对象较多时有很好的空间复杂度,但在查找搜索上消耗了时间负责度返回目录评析书上享元模式的例子(6.4.2)l被共享的仅有艺术家的名字字段,共享度较低返回目录6.5 外观(Facade)模式【实验】一、外观模式的由来二、外观模式的意图及适用性三、外观模式的结构及参与者四、应用举例五、效果分析返回目录6.5.1 外观模式的由来毕业生教务处公安处后勤处图书馆饭卡饭卡余额借书证借书证押金身份证、学生证派遣证学生证
42、毕业证、学位证返回目录6.5.1 外观模式的由来毕业生毕业手续代办处教务处后勤处图书馆公安处学生证 身份证 借书证 饭卡毕业证 学位证 派遣证 饭卡余额 借书证押金返回目录6.5.1 外观模式的由来返回目录6.5.1 外观模式的由来返回目录6.5.2 外观模式的意图及适用性为复杂子系统提供一个简单接口,定义一个高层接口,使子系统更加容易使用解除客户程序与抽象类具体实现部分的依赖性,有利于移植和更改当需要构建层次结构的子系统时,使用Faade模式定义每层的入口点。如果子系统间相互依赖,他们只需通过Faade进行通讯返回目录6.5.3 外观模式的结构和参与者返回目录6.5.3 外观模式的结构和参与
43、者Faadeu知道哪些子系统类负责处理请求u将客户的请求代理给适当的子系统对象Subsystem Classesu实现子系统的功能u处理由Faade 对象指派的任务u没有Faade的任何相关信息返回目录6.5.4 应用举例返回目录6.5.4 应用举例返回目录6.5.4 应用举例返回目录6.5.4 应用举例返回目录6.5.5 效果分析对客户端屏蔽子系统组件,减少客户端使用对象的数目实现了子系统与客户之间松耦合的关系,使得子系统组件的变化不会影响到客户并不限制客户应用子系统类返回目录6.6 代理(Proxy)模式一、代理模式的由来二、代理模式的意图及适用性三、代理模式的结构及参与者四、应用举例五、
44、效果分析返回目录6.6.1 代理模式的由来l某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.下面举两个具体的例子: l(1)如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片.返回目录6.6.1 代理模式的由来返回目录6.6.1 代理模式的由来 -图片代理大图片网页返回目录6.6.1 代理模式的由来l(2)如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy
45、来代替那个对象.远端对象远端对象代理返回目录6.6.1 代理模式的由来l 如何应对这种变化?如何提供一种机制让原本交互起来比较困难的两个对象实现畅通无阻地交流呢?并且从而保持系统的结构不随着需求改变而轻易改变?这就是要说的代理模式。l模式的意图 为其他对象提供一种代理以控制对这个对象的访问。返回目录6.6.2 代理模式的意图和适用性 -代理的不同模式l 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用代理模式。以下情况可以使用代理模式:l 1. 远程代理为一个对象在不同的地址空间提供局部代表。l 2. 虚代理在需要创建开销很大的对象时缓存对象信息。返回目录6.6.2 代理模式的意图和
46、适用性l 3. 保护代理控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。l 4.智能指引取代了简单的指针,它在访问对象时执行一些附加操作。它的典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它 。当第一次引用一个持久对象时,将它装入内存。在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。返回目录6.6.3 代理模式的结构和参与者返回目录6.6.3 代理模式的结构和参与者l 代理(代理(Proxy )1.保存一个引用1使得代理可以访问实体。2.提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。3.控制对实体的存
47、取,并可能负责创建和删除它。 4.其他功能依赖于代理的类型:远程代理(Remote Proxy)负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求。虚代理(Virtual Proxy)可以缓存实体的附加信息,以便延迟对它的访问。保护代理(Protection Proxy)检查调用者是否具有实现一个请求所必需的访问权限返回目录6.6.3 代理模式的结构和参与者l 对象(对象(Subject)定义ConcreteSubject和Proxy的共用接口,这样就在任何使用ConcreteSubject的地方都可以使用Proxy。l 具体对象(具体对象(ConcreteSubject)定
48、义Proxy所代表的实体返回目录6.6.4 应用举例 在软件系统中,我们无时不在跨越障碍,当我们访问网络上一台计算机的资源时,我们正在跨越网络,当我们去访问服务器上数据库时,我们又在跨越数据库访问障碍,同时还有网络障碍。跨越这些障碍有时候是非常复杂的,如果我们更多的去关注处理这些障碍问题,可能就会忽视了本来应该关注的业务逻辑问题,Proxy模式有助于我们去解决这些问题。 我们以一个简单的数学计算程序为例,这个程序只负责进行简单的加减乘除运算:返回目录6.6.4 应用举例 public class Math public double Add(double x,double y) return
49、x + y; public double Sub(double x,double y) return x - y; public double Mul(double x,double y) return x * y; public double Dev(double x,double y) return x / y; 返回目录6.6.4 应用举例如果说这个计算程序部署在我们本地计算机上,使用就非常之简单了,我们也就不用去考虑Proxy模式了。但现在问题是这个Math类并没有部署在我们本地,而是部署在一台服务器上,也就是说Math类根本和我们的客户程序不在同一个地址空间之内,我们现在要面对的是跨
50、越Internet这样一个网络障碍: 返回目录6.6.4 应用举例l 这时候调用Math类的方法就没有下面那么简单了,因为我们更多的还要去考虑网络的问题,对接收到的结果解包1等一系列操作。 public class App public static void Main() Math math = new Math(); / 对接收到的结果数据进行解包 double addresult = math.Add(2,3); double subresult = math.Sub(2,3); double mulresult = math.Mul(2,3); double devresult = m
51、ath.Dev(2,3); 返回目录6.6.4 应用举例l 为了解决由于网络等障碍引起复杂性,就引出了Proxy模式,我们使用一个本地的代理来替Math类打点一切,即为我们的系统引入了一层间接层,示意图如下:l 我们在MathProxy中对实现Math数据类的访问,让MathProxy来代替网络上的Math类,这样我们看到MathProxy就好像是本地Math类,它与客户程序处在了同一地址空间内返回目录6.6.4 应用举例 public class MathProxy private Math math = new Math(); / 以下的方法中,可能不仅仅是简单的调用Math类的方法 pu
52、blic double Add(double x,double y) return math.Add(x,y); public double Sub(double x,double y) return math.Sub(x,y); public double Mul(double x,double y) return math.Mul(x,y); public double Dev(double x,double y) return math.Dev(x,y); 返回目录6.6.4 应用举例l 现在可以说我们已经实现了对Math类的代理,存在的一个问题是我们在MathProxy类中调用了原实现
53、类Math的方法,但是Math并不一定实现了所有的方法,为了强迫Math类实现所有的方法,另一方面,为了我们更加透明的去操作对象,我们在Math类和MathProxy类的基础上加上一层抽象,即它们都实现与IMath接口,示意图如下: 返回目录6.6.4 应用举例 public interface IMath double Add(double x,double y); double Sub(double x,double y); double Mul(double x,double y); double Dev(double x,double y); Math类和MathProxy类分别实现I
54、Math接口: public class MathProxy : IMath / public class Math : IMath / 返回目录6.6.4 应用举例l 此时我们在客户程序中就可以像使用Math类一样来使用MathProxy类了: public class App public static void Main() MathProxy proxy = new MathProxy(); double addresult = proxy.Add(2,3); double subresult = proxy.Sub(2,3); double mulresult = proxy.Mul
55、(2,3); double devresult = proxy.Dev(2,3); 返回目录6.6.5 效果分析l Proxy模式根据种类不同,效果也不尽相同:l 1远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。远程代理又叫做大使(Ambassador)。好处是系统可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。客户完全可以认为被代理的对象是局域的而不是远程的,而代理对象承担了大部份的网络通讯工作。由于客户可能没有意识到会启动一个耗费时间的远程调用,因此客户没有必要的思想准备。l 2虚拟(Virt
56、ual)代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。使用虚拟代理模式的好处就是代理对象可以在必要的时候才将被代理的对象加载;代理可以对加载的过程加以必要的优化。当一个模块的加载十分耗费资源的情况下,虚拟代理的好处就非常明显。返回目录6.6.5 效果分析l 3Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。 l 4保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。保护代理的好处是它可以在运行时对用户的有关权限进行检查,然后在核实后决定将调
57、用传递给被代理的对象。l 5Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。 l 6防火墙(Firewall)代理:保护目标,不让恶意用户接近。 l 7同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。 l 8智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。返回目录代理模式举例lWindows快捷方式lWebservicel网页图片延时加载l.返回目录6.7 组合(Composite)模式一、组合模式的由来二、组合模式的意图及适用性三、组合
58、模式的结构及参与者四、应用举例五、效果分析返回目录6.7.1 组合模式的由来l思考:你如何管理一组对象实例返回目录6.7.1 组合模式的由来l 进一步思考:如果对象构成了一个层次结构,又该如何管理?返回目录6.7.1 组合模式的由来CBADA B C D返回目录6.7.1 组合模式的由来l一条命令在多个对象上激发复杂的或递归的行为。l用同样的方法处理对象的集合和其中的特定子对象l对组合对象执行的这些操作将向下传递到所有的组成对象l把一批子对象组织成树形结构,并且使整棵树都可被遍历 用户需要控制整个组合对象 用户需要控制组合对象中的单个部分。 用户界面应当一致 返回目录6.7.1 组合模式的由来
59、表达部分与整体的树形结构机箱计算机显示器键盘鼠标主板CPU硬盘电源显卡网卡返回目录6.7.1 组合模式的由来 抽象u 单一对象(Leaf):键盘、鼠标、显示器、硬盘、电源、 CPU、显卡、网卡u 组合对象(Composite):计算机、机箱、主板u 部件(Component):单一对象与组合对象的统称 组合对象既可以包括单一对象,也可以包括组合对象返回目录6.7.3组合模式的结构及参与者 -类图返回目录6.7.3组合模式的结构及参与者 -对象图返回目录6.7.2 组合模式的意图及适用性意图将对象组合成树形结构表示“部分-整体”的层次结构。 Composite是的用户对单个对象和组合对象的使用具有一致性。以下情况可以使用组合模式 表示对象的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 浙江省湖州三校2026届高三高考仿真模拟卷(一)化学试题含解析
- 基于深度学习的关节骨软骨瘤深度可解释性分析-洞察与解读
- 感冒止咳糖浆的生物等效性评估与临床应用价值探讨-洞察与解读
- 数字twin技术驱动的产业生态重构-洞察与解读
- 2026年西棠供应链管理服务合同二篇
- 2026年高考生物新课标一卷基础培训考试综合试卷
- 基于自然语言处理的政务合同智能审查优化策略
- 虎门人事劳务外包合同
- 扣件式钢管脚手架平网使用安全技术交底
- 幼儿园大班语文试题含答案
- 药理学第二十五章抗心绞痛药教案
- 洗刷餐具劳动课件
- TCCES10-2020建筑外墙空调器室外机平台技术规程
- 2025年10月自考14234室内构造与材料学.试题及答案
- 高校外聘教师管理标准及考核办法
- T-CECS 1049-2022 隧道衬砌拱顶带模注浆材料应用技术规程
- 2025湖南省高级政工师考试真题含答案
- 房屋拆除专项施工流程方案
- 化妆品乳化车间培训
- 热点主题作文写作指导:“小我”与“大我”(审题指导与例文)
- 2025年中小学国防教育知识竞赛活动考试题库200题(含答案)
评论
0/150
提交评论