OOAD之设计模式-结构模式

来源:互联网 发布:js 数字转换为汉字 编辑:程序博客网 时间:2024/05/22 02:29

一、结构模式

用于组织类对象之间的结构

1.1外观模式facade

为了便于用户使用,提供一键式对外操作方法。对于使用者来说,只需要知道怎么调用方法就行了。不需要知道内部设置和实现。

就像傻瓜相机一样。

目的是:简化客户程序与子系统之间的交互接口。

效果及实现要点
1.Façade模式对客户屏蔽了子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
2.Façade模式实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。松耦合关系使得子系统的组件变化不会影响到它的客户。
3.如果应用需要,它并不限制它们使用子系统类。因此你可以在系统易用性与通用性之间选择。
4.通过一个高层接口让子系统和客户端不发生直接关联,使客户端不受子系统变化的影响。
5.Facade不仅仅针对代码级别,在构架上,特别是WEB应用程序的构架上,Facade的应用非常普遍。
适用性
1.为一个复杂子系统提供一个简单接口。
2.提高子系统的独立性。
3.在层次化结构中,可以使用Facade模式定义系统中每一层的入口。
4.从代码角度来说,如果你的程序有多个类是和一组其它接口发生关联的话可以考虑在其中加一个外观类型。
5.从应用角度来说,如果子系统的接口是非常细的,调用方也有大量的逻辑来和这些接口发生关系,那么就可以考虑使用Facade把客户端与子系统的直接耦合关系进行化解。你可能会说,子系统改了外观不是照样改?的确是需要改,但是如果客户端本身的工作已经比较复杂,或者说可能有多个需要调用外观的地方,这个时候外观的好处就体现了。

 

1.2装饰器模式decorator

Decorator模式,描述的就是对象间可能存在的多种组合方式,这种组合方式是一种装饰者与被装饰者之间的关系,因此封装这种组合方式,抽象出专门的装饰对象正是“封装变化”的体现。

目的是:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

为了防止类爆炸(多次复用,叠加多次时)修饰类可以多次修饰主体类,可以叠加修饰。但是主体类低位不变,对外体现仍为主体。

装饰类继承主体类,并且组合一个主体类(反向组合)

Decorator模式的优点是提供了比继承更加灵活的扩展,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。

让装饰角色还继承抽象构件角色也是装饰模式最大的特点,目的就是给抽象构件增加职责,对外表现为装饰后的构件。

让装饰角色拥有构件角色实例的目的就是让构件能被多个装饰对象来装饰。

在具体应用中可以灵活一点,不一定要有抽象构件和装饰角色。但是,装饰对象继承装饰对象并且拥有它实例的两大特点需要体现。

透明装饰一般通过在基类方法前后进行扩充实现,半透明装饰一般通过新的接口实现。

 

public abstract class 咖啡 {private int cost;public void setCost(int cost){this.cost = cost;}public abstract int getCost();}


 

public abstract class 配料 extends 咖啡{private 咖啡 coffee;public 配料(咖啡 coffee){this.coffee = coffee;}public 咖啡 getCoffee(){return this.coffee;}}
public class 卡布基诺 extends 咖啡{private int cost = 19;@Overridepublic int getCost() {// TODO Auto-generated method stubreturn this.cost;}}
public class 蓝山 extends 咖啡 {private int cost = 21;@Overridepublic int getCost() {// TODO Auto-generated method stubreturn this.cost;}}


 

public class 奶 extends 配料 {public 奶(咖啡 coffee){super(coffee);}@Overridepublic int getCost() {// TODO Auto-generated method stubreturn this.getCoffee().getCost() + 5;}}


 

public class 爱心 extends 配料 {public 爱心(咖啡 coffee){super(coffee);}@Overridepublic int getCost() {// TODO Auto-generated method stubreturn this.getCoffee().getCost() + 50;}}
 

1.3代理模式proxy

用户与要访问的目标是隔离的,为了访问而采用中间代理来实现。同时还能实现功能的新增,甚至替换掉原来的功能,但是用户不会有任何感觉。

代理一般继承与目标一致的父类或者目标本类。重写父类方法,首尾添加,中间调用父类的方法。

在软件系统中,有些对象有时候由于跨越网络或者其他的障碍,而不能够或者不想直接访问另一个对象,如果直接访问会给系统带来不必要的复杂性,这时候可以在客户程序和目标对象之间增加一层中间层,让代理对象来代替目标对象打点一切。这就是本文要说的Proxy模式。

目的:为其他对象提供一种代理以控制对这个对象的访问。

Proxy模式根据种类不同,效果也不尽相同:

1.远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。远程代理又叫做大使(Ambassador)。好处是系统可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。客户完全可以认为被代理的对象是局域的而不是远程的,而代理对象承担了大部份的网络通讯工作。由于客户可能没有意识到会启动一个耗费时间的远程调用,因此客户没有必要的思想准备。

2.虚拟(Virtual)代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。使用虚拟代理模式的好处就是代理对象可以在必要的时候才将被代理的对象加载;代理可以对加载的过程加以必要的优化。当一个模块的加载十分耗费资源的情况下,虚拟代理的好处就非常明显。

3.Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。

4.保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。保护代理的好处是它可以在运行时间对用户的有关权限进行检查,然后在核实后决定将调用传递给被代理的对象。

5.Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

6.防火墙(Firewall)代理:保护目标,不让恶意用户接近。

7.同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。

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

 

1.4桥梁模式

Bridge模式封装对象实现的依赖关系。将抽象部分与它的实现部分分离,使它们都可以独立地变化。抽象部分是指不同的事物在概念层次上的联系。分离是指让各部分的行为各自独立,或至少显式指出关联。

多个变化点无主次之分,一个类组合多个变化点(需要时,也可以变化为装饰器)

同时可以实现当一化职责,减少类数目,防止排列组合式的类爆炸。

目的:将每个抽象部分与实现部分分离,使它们都可以独立的变化。进而大大减少类的数目。最后再组合为一个整体,对外公布。

效果及实现要点
1.Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。
2.所谓抽象和实现沿着各自维度的变化,即“子类化”它们,得到各个子类之后,便可以任意它们,从而获得不同平台上的不同型号。
3.Bridge模式有时候类似于多继承方案,但是多继承方案往往违背了类的单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
4.Bridge模式的应用一般在“两个非常强的变化维度”,有时候即使有两个变化的维度,但是某个方向的变化维度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。
适用性
在以下的情况下应当使用桥梁模式:
1.如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的联系。
2.设计要求实现化角色的任何改变不应当影响客户端,或者说实现化角色的改变对客户端是完全透明的。
3.一个构件有多于一个的抽象化角色和实现化角色,系统需要它们之间进行动态耦合。
4.虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。

它很好的符合了开闭原则和优先使用对象,而不是继承这两个面向对象原则。

public abstract class Shap {private Line line;public Line getLine() {return line;}public void setLine(Line line) {this.line = line;}public abstract void paint();}


 

public abstract class Line {public abstract void draw();}


 

public class Rectangle extends Shap {private int x;private int y;private int width;private int high;@Overridepublic void paint() {// TODO Auto-generated method stubSystem.out.println("计算矩形的大小、位置");this.getLine().draw();}}


 

public class Circle extends Shap{private int x;private int y;private int r;@Overridepublic void paint() {// TODO Auto-generated method stubSystem.out.println("计算圆的大小、位置");this.getLine().draw();}}


 

public class DotedLine extends Line {@Overridepublic void draw() {// TODO Auto-generated method stubSystem.out.println("虚线绘制");}}


 

public class FullLine extends Line {@Overridepublic void draw() {// TODO Auto-generated method stubSystem.out.println("实线绘制");}}

 

1.5适配器模式adapter

基于已知类或接口功能,满足客户的需求。

继承一个类,在组合另外的类。实现通过一个类访问多个类的行为。综合利用已有的资源。

如果已经有了接口,那么创建一个类组合2个接口的实现类。重载接口的方法,方法中调用实现类的相应方法。

 

原创粉丝点击