【设计模式】结构型模式——七种
适配器模式
适配器(adapter)模式,将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原来由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式有类的适配器模式和对象的适配器模式两种形式。1、为什么会出现适配器模式?
在实际的开发过程中,由于应用环境的变化(如使用开发语言的变化),需要实现在新的环境中没有现存对象可以满足,但是其他环境却存在这样现存的对象。为了将现存对象在新的环境中进行调用,由此产生了适配器模式。使得新环境中不需要重复实现已经存在了的实现而很好的把现有对象(指原来环境中的现有对象)加入到新环境中来使用。
2、优点
- 可以在不修改原有代码的基础上来复用现有类,符合“开闭原则”。
- 可以重新定义adapter(被适配的类)的部分行为,因为在类适配器模式中,adapter是adaptee的子类
- 仅仅引入一个对象,并不需要额外的字段来引用adaptee实例
3、缺点
- 用一个具体的adapter类对adaptee和target进行匹配,当如果想要匹配一个类以及他的子类时,类的适配器模式就不能胜任了。因为类的适配器模式中没有引入adaptee的实例,光调用this.specificRequest方法并不能去调用他对应子类的specificRequest方法。
- 采用了“多继承”的实现方式,带来了不良的高耦合。
桥接模式
1、定义
桥接模式即将抽象部分与实现部分脱耦,使得他们独立变化互不影响到对方。
2、目的
桥接的目的是使得抽象化与实现化部分分离,根据面向对象的封装变化的原则,我们可以把实现部分的变化封装到另一个类中。
3、优点
- 把抽象接口与其实现解耦
- 抽象和实现可以独立扩展,不会影响到对方
- 实现细节对客户透明,对用于隐藏了具体实现细节
4、缺点
增加了系统的复杂度
装饰模式
装饰者模式以对客户透明的方式动态地给一个对象附加更多的责任,装饰者模式相比生成子类可以更灵活的增加功能。
装饰者模式采用对象组合而非继承的方式实现了再运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。同时它很好的符合面向对象设计原则中的“优先使用对象组合而非继承”和“开发封闭原则”。
1、优点
- 装饰者模式和继承的目的都是扩展对象的功能,但是装饰者模式比继承更灵活
- 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
- 装饰者模式有很好的可扩展性
2、缺点
装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变得更复杂,并且更多的对象会使得差错变得困难,特别是这些对象看上去都很像。
3、何时使用装饰者模式?
- 需要扩展一个类的功能或给一个类增加附加责任
- 需要动态的给一个对象增加功能,这些功能可以再动态的撤销
- 需要增加由一个基本功能的排列组合而产生的非常大量的功能
组合模式
组合模式允许将对象组合成树形结构来表现“部分——整体”的层次结构,使得客户以一致的方式处理单个对象以及对象的组合。
组合模式实现的最关键的地方是:简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。
1、优点
- 组合模式使得客户端代码可以一致的处理对象和对象容器,无需处理单个对象或者组合的对象容器
- 将客户端代码与复杂的对象容器结构解耦
- 可以更容易的往组合对象中加入新的构件
2、缺点
使得设计更为复杂,客户端需要更多时间来理清类之间的层次关系。
3、何时使用组合模式?
当需求中是体现部分与整体层次结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,这时应该考虑使用组合模式。
外观模式
外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用,使用外观模式时,我们创建了一个统一的类,用来包装子系统中一个或多个复杂的类,客户端可以直接通过外观类来调用内部子系统中的方法,从而外观模式让客户和子系统之间避免了耦合。
1、为什么会出现外观模式?
在软件开发过程中,客户端程序经常会与复杂系统的内部子系统进行耦合,从而导致客户端程序随着子系统的变化而变化,然而为了将复杂系统的内部子系统与客户端之间的依赖解耦,从而产生了外观模式。
2、外观模式与适配器模式的区别
适配器模式是将一个对象包装起来以改变其接口,而外观模式是将一群对象“包装”起来以简化其接口。他们的意图是不一样的,适配器模式是将接口转换为不同接口,而外观模式是提供一个统一的接口来简化接口。
3、优点
- 外观模式对客户屏蔽了子系统组件,从而简化了接口,减少了客户处理的对象数目并使子系统的使用更加简单
- 外观模式实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件是紧耦合的,松耦合使得子系统的组件变化不会影响到他的客户
- 外观模式可以解决层结构分离,降低系统耦合度和为新旧系统交互提供接口的功能。
4、缺点
如果增加新的子系统可能需要修改外观类或客户端的源代码,就违背了“开发——封闭的原则”
5、解决的问题
享元模式主要用来解决由于大量的细粒度对象所造成的内存开销的问题,他在实际的开发过程中并不常用,可以作为底层的提升性能的一种手段。
享元模式
享元模式是指运用共享及时有效的支持大量细粒度的对象。
1、何时使用享元模式?
享元模式可以避免大量非常相似类的开销,在软件开发中如果需要生成大量细粒度的类实例来表示数据,如果这些实例除了几个参数外基本都是相同的,这时候就可以使用享元模式来大幅度减少需要实例化类的数量。
如果能把这些参数(指这些类实例的不同参数)移动类实例外面,在方法调用时将他们传递进来,这样就可以通过共享大幅度的减少单个实例的数目。(把类实例外面的参数称为享元对象的外部状态,把在享元对象内部定义称为内部状态)
内部状态:在享元对象的内部并且不会随着环境的改变而改变的共享部分
外部状态:随环境改变而改变的,不可以共享的状态
2、优点
降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力
3、缺点
- 为了使对象可以共享,需要将一些状态外部化,这将使得程序的逻辑更加复杂,使系统复杂化
- 享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
代理模式
代理模式就是给某个对象提供一个代理,并由代理对象控制对原对象的引用。在一些情况下,一个客户不想或者不能直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。1、为什么会出现代理模式?
在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象,然后客户端只需要访问代理对象,由代理对象去帮我们去请求目标对象并返回结果给客户端。
2、优点
- 代理模式能够将调用用于真正被调用的对象隔离,在一定程度上降低了系统的耦合度
- 代理对象在客户端和目标对象之间起到一个中介的作用,这样可以起到对目标对象的保护,代理对象可以在对目标对象发出请求之前进行一个额外的操作,例如权限检查
3、缺点
- 由于在客户端和真实主题之间增加了一个代理对象,所以对造成请求的处理速度变慢
- 实现代理类也需要增加额外的工作,从而增加了系统的实现复杂度