设计模式-结构型模式
7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源
1,适配器模式(Adapter)
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。
例如:
有一个Source类,拥有一个方法,待适配,目标适配接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里
Source类:
TargeTable接口:
Adapter类:
测试:
结果:
对象适配器模式:
基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。
Adapter2:
测试:
结果:
接口适配器模式:
有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。
TargeTable接口:
TargeTable接口:
实现TargeTable接口的抽象类:abs_TargeTable:
继承abs_TargeTable抽象类的2个子类:
测试:
结果:
三种适配器模式的应用场景:
类的适配器模式:
当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
对象的适配器模式:
当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个类,持有原类的一个实例,在该类的方法中,调用实例的方法就行。
接口的适配器模式:
当不希望实现一个接口中所有的方法时,可以创建一个抽象类,实现所有方法,我们写别的类的时候,继承抽象类即可。
2,装饰模式(Decorator)
装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例
例如:
Source类是被装饰类,SourceDecorator类是一个装饰类,可以为Source类动态的添加一些功能:
TargeTable接口:
例如:
Source类是被装饰类,SourceDecorator类是一个装饰类,可以为Source类动态的添加一些功能:
TargeTable接口:
Source被装饰类:
SourceDecorator装饰类:
测试:
结果:
装饰器模式的应用场景:
1、需要扩展一个类的功能。
2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
缺点:产生过多相似的对象,不易排错!
3,代理模式(Proxy)
代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。
TargeTable接口:
Source类:
Proxy代理类:
测试:
结果:
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
TargeTable接口:
Source类:
Proxy代理类:
测试:
结果:
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
4,外观模式(Facade)
为子系统中的一组接口提供一个统一接口。Facade模式定义了一个高层接口,这个接口使得这子系统更容易使用。外观模式是为了解决类与类之间的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度:
DeawerOne类:
DrawerTwo类:
Facade类:
测试Test:
结果:
5,桥接模式(Bridge)DeawerOne类:
DrawerTwo类:
Facade类:
测试Test:
结果:
桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化。桥接的用意是:将抽象化与实现化解耦,使得二者可以独立变化,像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不用动,原因就是JDBC提供统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了。
例子:
定义一个链接数据库的接口UrlLink:
2个实现UrlLink接口的实现类:
定义一个抽象的桥接类UrlBridge:
一个继承桥接类的MyUrlBridge类:
测试Test:
结果:
例子:
定义一个链接数据库的接口UrlLink:
2个实现UrlLink接口的实现类:
定义一个抽象的桥接类UrlBridge:
一个继承桥接类的MyUrlBridge类:
测试Test:
结果:
6,组合模式(Composite)
组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便。
例如:
Tree类:
TreeNode类:
Test:
结果:
使用场景:将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。
例如:
Tree类:
TreeNode类:
Test:
结果:
使用场景:将多个对象组合在一起进行操作,常用于表示树形结构中,例如二叉树,数等。
7,享元模式(Flyweight)
享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用。在JAVA语言中,String类型就是使用了享元模式。
享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。
一个内蕴状态是存储在享元对象内部的,并且是不会随环境的改变而有所不同。因此,一个享元可以具有内蕴状态并可以共享。
一个外蕴状态是随环境的改变而改变的、不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的。
实例:
FlyWeight接口,规定出所有具体享元角色需要实现的方法
ConcreteFlyweight实现FlyWeight接口,负责对内藴状态的元素分配空间
FlyWeightFactory一个工厂类,责创建和管理享元角色
Test测试类:
享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。
一个内蕴状态是存储在享元对象内部的,并且是不会随环境的改变而有所不同。因此,一个享元可以具有内蕴状态并可以共享。
一个外蕴状态是随环境的改变而改变的、不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的。
实例:
FlyWeight接口,规定出所有具体享元角色需要实现的方法
ConcreteFlyweight实现FlyWeight接口,负责对内藴状态的元素分配空间
FlyWeightFactory一个工厂类,责创建和管理享元角色
Test测试类:
结果:
虽然工厂类创建了三个享元对象,但是实际创建的享元对象只有两个,这就是共享的含义。
参考质料:http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html