设计模式 学习 4:

七个结构型模式之4(装饰模式,外观模式,享元模式,代理模式)

装饰模式:

Sunny软件公司基于面向对象技术开发了一套图形界面构件库VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特效显示效果,如带滚动条的窗体、带黑色边框的文本框、既带滚动条又带黑色边框的列表框等等,因此经常需要对该构件库进行扩展以增强其功能

如何提高图形界面构件库性的可扩展性并降低其维护成本是Sunny公司开发人员必须面对的一个问题?

答案:


//抽象界面构件类:抽象构件类,为了突出与模式相关的核心代码,对原有控件代码进行了大量的简化

abstract class Component

{

public  abstract void display();

}

//窗体类:具体构件类

class Window extends Component

{

public  void display()

{

System.out.println("显示窗体!");

}

}

//文本框类:具体构件类

class TextBox extends Component

{

public  void display()

{

System.out.println("显示文本框!");

}

}

//列表框类:具体构件类

class ListBox extends Component

{

public  void display()

{

System.out.println("显示列表框!");

}

}

//构件装饰类:抽象装饰类

class ComponentDecorator extends Component

{

       private Component component;  //维持对抽象构件类型对象的引用

 

       public ComponentDecorator(Component  component)  //注入抽象构件类型的对象

       {

              this.component = component;

       }

       public void display()

       {

              component.display();

       }

}

//滚动条装饰类:具体装饰类

class ScrollBarDecorator extends  ComponentDecorator

{

       public ScrollBarDecorator(Component  component)

       {

              super(component);

       }

 

       public void display()

       {

              this.setScrollBar();

              super.display();

       }

public  void setScrollBar()

{

System.out.println("为构件增加滚动条!");

}

}

//黑色边框装饰类:具体装饰类

class BlackBorderDecorator extends  ComponentDecorator

{

       public BlackBorderDecorator(Component  component)

       {

              super(component);

       }

 

       public void display()

       {

              this.setBlackBorder();

              super.display();

       }

public  void setBlackBorder()

{

System.out.println("为构件增加黑色边框!");

}

}

编写如下客户端测试代码:


class Client

{

public  static void main(String args[])

{

              Component component,componentSB;  //使用抽象构件定义

              component = new Window(); //定义具体构件

              componentSB = new  ScrollBarDecorator(component); //定义装饰后的构件

              componentSB.display();

}

}


class SubSystemA

{

public void MethodA()

{

//业务实现代码

}

}

class SubSystemB

{

public void MethodB()

{

//业务实现代码

}

}

class SubSystemC

{

public void MethodC()

{

//业务实现代码

}

}

class Facade

{

private SubSystemA obj1 = new SubSystemA();

private SubSystemB obj2 = new SubSystemB();

private SubSystemC obj3 = new SubSystemC();

public void Method()

{

obj1.MethodA();

obj2.MethodB();

obj3.MethodC();

}

}

class Program

{

static void Main(string[] args)

{

Facade facade = new Facade();

facade.Method();

}

}

享元模式

Sunny软件公司欲开发一个围棋软件,Sunny软件公司开发人员通过对围棋软件进行分析,发现在围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。如果将每一个棋子都作为一个独立的对象存储在内存中,将导致该围棋软件在运行时所需内存空间较大,如何降低运行代价、提高系统性能是Sunny公司开发人员需要解决的一个问题

IgoChessman充当抽象享元类,BlackIgoChessman和WhiteIgoChessman充当具体享元类,IgoChessmanFactory充当享元工厂类。完整代码如下所示:

[java] view plain copy

  1. import java.util.*;
  2. //围棋棋子类:抽象享元类
  3. abstract class IgoChessman {
  4. public abstract String getColor();
  5. public void display() {
  6. System.out.println("棋子颜色:" + this.getColor());
  7. }
  8. }
  9. //黑色棋子类:具体享元类
  10. class BlackIgoChessman extends IgoChessman {
  11. public String getColor() {
  12. return "黑色";
  13. }
  14. }
  15. //白色棋子类:具体享元类
  16. class WhiteIgoChessman extends IgoChessman {
  17. public String getColor() {
  18. return "白色";
  19. }
  20. }
  21. //围棋棋子工厂类:享元工厂类,使用单例模式进行设计
  22. class IgoChessmanFactory {
  23. private static IgoChessmanFactory instance = new IgoChessmanFactory();
  24. private static Hashtable ht; //使用Hashtable来存储享元对象,充当享元池
  25. private IgoChessmanFactory() {
  26. ht = new Hashtable();
  27. IgoChessman black,white;
  28. black = new BlackIgoChessman();
  29. ht.put("b",black);
  30. white = new WhiteIgoChessman();
  31. ht.put("w",white);
  32. }
  33. //返回享元工厂类的唯一实例
  34. public static IgoChessmanFactory getInstance() {
  35. return instance;
  36. }
  37. //通过key来获取存储在Hashtable中的享元对象
  38. public static IgoChessman getIgoChessman(String color) {
  39. return (IgoChessman)ht.get(color);
  40. }
  41. }

编写如下客户端测试代码:

  1. class Client {
  2. public static void main(String args[]) {
  3. IgoChessman black1,black2,black3,white1,white2;
  4. IgoChessmanFactory factory;
  5. //获取享元工厂对象
  6. factory = IgoChessmanFactory.getInstance();
  7. //通过享元工厂获取三颗黑子
  8. black1 = factory.getIgoChessman("b");
  9. black2 = factory.getIgoChessman("b");
  10. black3 = factory.getIgoChessman("b");
  11. System.out.println("判断两颗黑子是否相同:" + (black1==black2));
  12. //通过享元工厂获取两颗白子
  13. white1 = factory.getIgoChessman("w");
  14. white2 = factory.getIgoChessman("w");
  15. System.out.println("判断两颗白子是否相同:" + (white1==white2));
  16. //显示棋子
  17. black1.display();
  18. black2.display();
  19. black3.display();
  20. white1.display();
  21. white2.display();
  22. }
  23. }

代理模式

问题:

某软件公司承接了某信息咨询公司的收费商务信息查询系统的开发任务,该系统的基本需求如下:

       (1) 在进行商务信息查询之前用户需要通过身份验证,只有合法用户才能够使用该查询系统;

       (2) 在进行商务信息查询时系统需要记录查询日志,以便根据查询次数收取查询费用。

       该软件公司开发人员已完成了商务信息查询模块的开发任务,现希望能够以一种松耦合的方式向原有系统增加身份验证和日志记录功能,客户端代码可以无区别地对待原始的商务信息查询模块和增加新功能之后的商务信息查询模块,而且可能在将来还要在该信息查询模块中增加一些新的功能。

       试使用代理模式设计并实现该收费商务信息查询系统。

代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层

在实际开发过程中,代理类的实现比上述代码要复杂很多,代理模式根据其目的和实现方式不同可分为很多种类,其中常用的几种代理模式简要说明如下:

 (1) 远程代理(Remote Proxy)为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又称为大使(Ambassador)

 (2) 虚拟代理(Virtual Proxy)如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。

 (3) 保护代理(Protect Proxy)控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。

 (4) 缓冲代理(Cache Proxy)为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

   (5) 智能引用代理(Smart Reference Proxy)当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等

远程代理(Remote Proxy)是一种常用的代理模式,它使得客户端程序可以访问在远程主机上的对象,远程主机可能具有更好的计算性能与处理速度,可以快速响应并处理客户端的请求。远程代理可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。客户端完全可以认为被代理的远程业务对象是在本地而不是在远程,而远程代理对象承担了大部分的网络通信工作,并负责对远程业务方法的调用。

远程代理示意图如图15-5所示,客户端对象不能直接访问远程主机中的业务对象,只能采取间接访问的方式。远程业务对象在本地主机中有一个代理对象,该代理对象负责对远程业务对象的访问和网络通信,它对于客户端对象而言是透明的。客户端无须关心实现具体业务的是谁,只需要按照服务接口所定义的方式直接与本地主机中的代理对象交互即可。

虚拟代理(Virtual Proxy)也是一种常用的代理模式,对于一些占用系统资源较多或者加载时间较长的对象,可以给这些对象提供一个虚拟代理。在真实对象创建成功之前虚拟代理扮演真实对象的替身,而当真实对象创建之后,虚拟代理将用户的请求转发给真实对象。

通常,在以下两种情况下可以考虑使用虚拟代理:

(1) 由于对象本身的复杂性或者网络等原因导致一个对象需要较长的加载时间,此时可以用一个加载时间相对较短的代理对象来代表真实对象。通常在实现时可以结合多线程技术,一个线程用于显示代理对象,其他线程用于加载真实对象。这种虚拟代理模式可以应用在程序启动的时候,由于创建代理对象在时间和处理复杂度上要少于创建真实对象,因此,在程序启动时,可以用代理对象代替真实对象初始化,大大加速了系统的启动时间。当需要使用真实对象时,再通过代理对象来引用,而此时真实对象可能已经成功加载完毕,可以缩短用户的等待时间。

(2) 当一个对象的加载十分耗费系统资源的时候,也非常适合使用虚拟代理。虚拟代理可以让那些占用大量内存或处理起来非常复杂的对象推迟到使用它们的时候才创建,而在此之前用一个相对来说占用资源较少的代理对象来代表真实对象,再通过代理对象来引用真实对象。为了节省内存,在第一次引用真实对象时再创建对象,并且该对象可被多次重用,在以后每次访问时需要检测所需对象是否已经被创建,因此在访问该对象时需要进行存在性检测,这需要消耗一定的系统时间,但是可以节省内存空间,这是一种用时间换取空间的做法。

无论是以上哪种情况,虚拟代理都是用一个“虚假”的代理对象来代表真实对象,通过代理对象来间接引用真实对象,可以在一定程度上提高系统的性能。

时间: 2024-12-23 21:59:30

设计模式 学习 4:的相关文章

设计模式学习总结

本文是对各处设计模式示例的总结概括和简化,主要参考 http://blog.csdn.net/zhangerqing/article/details/8194653 直接看本文估计比较枯燥无聊,因为没图~~??,建议对设计模式有兴趣的先看看上面的博文,或者基础比较好可直接移到最底下看下我的各模式一句话概括总结,有什么意见建议欢迎提出~~~~~~~~~~ 总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式.结构型模式,共七种:适配器模式.装饰

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl

java/android 设计模式学习笔记(10)---建造者模式

这篇博客我们来介绍一下建造者模式(Builder Pattern),建造者模式又被称为生成器模式,是创造性模式之一,与工厂方法模式和抽象工厂模式不同,后两者的目的是为了实现多态性,而 Builder 模式的目的则是为了将对象的构建与展示分离.Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程.一个复杂的对象有大量的组成部分,比如汽车它有车轮.方向盘.发动机.以及各种各样的小零件,要将这些部件装配成一辆汽车,这个装配过

java/android 设计模式学习笔记(一)---单例模式

前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使用的时候也会有一些坑. PS:对技术感兴趣的同鞋加群544645972一起交流 设计模式总目录 java/android 设计模式学习笔记目录 特点 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式的使用很广泛,比如:线程池(threadpool).缓存(cache).对

java/android 设计模式学习笔记(7)---装饰者模式

这篇将会介绍装饰者模式(Decorator Pattern),装饰者模式也称为包装模式(Wrapper Pattern),结构型模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时它也是继承关系的一种替代方案之一,但比继承更加灵活.在现实生活中也可以看到很多装饰者模式的例子,或者可以大胆的说装饰者模式无处不在,就拿一件东西来说,可以给它披上无数层不一样的外壳,但是这件东西还是这件东西,外壳不过是用来扩展这个东西的功能而已,这就是装饰者模式,装饰者的这个角色也许各不相同但是被装饰的对

设计模式学习难度系数排名

这是yqj2065感觉的每个设计模式学习难度系数. 刘伟(Sunny)先生有一个5分制的学习难度,列在模式名称之后. 有几个模式的评价差别很大,抽象工厂模式和享元模式给4分/5,而单例模式1分/5.冠军是一样的. 学习难度系数: ☆☆☆☆☆ ☆☆☆☆☆ 依赖注入模式 静态工厂模式 2 策略模式 1 ★☆☆☆☆ ☆☆☆☆☆ 工厂方法模式 2 模板方法模式 2 适配器模式    2 责任链模式   3 外观模式 1 ★★☆☆☆ ☆☆☆☆☆ 抽象工厂模式  4 桥接模式  3 迭代器    3 享元模

设计模式学习--Singleton

What Singleton:保证一个类仅有一个实例,并提供一个访问它的全局访问点. Why Singletion是我比较熟悉的设计模式之一,在平常的开发过程中,也曾几次用到,它主要适用于如下场景: 1.当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时. 2.当这个唯一实例应该是通过子类可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时. 在系统设计中,在涉及系统资源的管理时,往往会被设计成Singletion模式,比如缓存.日志对象.线程池.对话框等等. How 假设如下场

设计模式学习03—抽象工厂模式

1.动机与定义 工厂模式中,一个工厂仅仅能提供一个或一类产品,当产品种类较多,形成产品系列(比方我们要创建跨平台的button,菜单,文本框等等一系列GUI控件: 单纯使用工厂模式会产生大量工厂,并且后期维护也不方便,我们能够从产品中找到规律,假设产品等级相对固定,以后仅仅会新增产品族,那么我们就能够把整个产品族放到一个工厂创建,以后新增其它系统产品族也很方便,例如以下图: 这样的模式就是抽象工厂,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则须要面对多个产品等级结构,一个工厂等级结构能

大话设计模式学习笔记——面向对象基础

前言 好记性不如烂"笔头"系列--大话设计模式学习笔记 目录 面向对象基础 面向对象基础 什么是类与实例 一切事物皆为对象,即所有的东西老师对象,对象就是可以看到.感觉到.听到.触摸到.尝到.或闻到的东西.准确地说,对象是一个自包含的实体,用一组可识别的特性和行为来标识.面向对象编程,英文叫 Object-Oriented Programming,其实就是针对对象来进行编程的意思.类就是具有相同属性和功能的对象的抽象集合.实例就是一个真实的对象.比如我们属于'人'类,而个人就是'人'类

java/android 设计模式学习笔记(13)---享元模式

这篇我们来介绍一下享元模式(Flyweight Pattern),Flyweight 代表轻量级的意思,享元模式是对象池的一种实现.享元模式用来尽可能减少内存使用量,它适合用于可能存在大量重复对象的场景,缓存可共享的对象,来达到对象共享和避免创建过多对象的效果,这样一来就可以提升性能,避免内存移除和频繁 GC 等. 享元模式的一个经典使用案例是文本系统中图形显示所用的数据结构,一个文本系统能够显示的字符种类就是那么几十上百个,那么就定义这么些基础字符对象,存储每个字符的显示外形和其他的格式化数据