设计模式中的结构类模式
结构类模式包括适配器模式、桥梁模式、组合模式、装饰模式、门面模式、享元模式和代理模式。
- 适配器模式:修饰非血缘关系类,把一个非本家族的对象伪装成本家族的对象,因此它的本质还是非相同接口的对象。(适配器)
- 桥梁模式:即桥接模式,将抽象和实现解耦,使得两者可以独立地变化。(公司只需要挣钱,不需要知道挣钱时每一步的具体过程)
- 组合模式:用来描述部分与整体的关系,使得用户对单个对象和组合对象的使用具有一致性。(一般表示树型结构,树叶与树枝)
- 装饰模式:修饰血缘关系类,对类的功能进行加强或减弱,着重类的功能变化。(运动员添加一个氮气加速跑功能)
- 门面模式:即外观模式,要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。(房子内的所有对象都需要走大门)
- 享元模式:使用共享对象可有效地支持大量的细粒度的对象。(一个对象拆分成两个状态,内部状态(可共享)和外部状态(会改变))
- 代理模式:修饰血缘关系类,着重对代理过程的控制。在不改变接口的前提下,对过程进行控制。(类似代理人)
代理模式VS装饰模式
装饰模式就是代理模式的一个特殊应用。
共同点:都具有相同的接口。
- 代理模式实现要代理的类的接口。
- 装饰模式实现要装饰的类的接口。
不同点:
- 代理模式着重对代理过程的控制。
- 装饰模式则是对类的功能进行加强或减弱,它着重类的功能变化。
(1)代理模式
如果你想看一个著名运动员的跑步训练,运动员肯定不搭理你,那么此时如果你跟他的代理人很熟,你就可以征得代理人同意,让他帮你可以看到运动员的训练。
public interface IRunner {
public void run();
}
public class Runner implements IRunner {
@Override
public void run() {
System.out.println("宝贝儿跑起来...");
}
}
import java.util.Random;
public class RunnerAgent implements IRunner {
private IRunner runner;
public RunnerAgent(IRunner runner) {
this.runner = runner;
}
@Override
public void run() {
Random random = new Random();
if (random.nextBoolean()) {
System.out.println("代理人同意");
this.runner.run();
} else {
System.out.println("代理人不同意");
}
}
}
public class Client {
public static void main(String[] args) {
IRunner runner = new Runner();
IRunner runnerAgent = new RunnerAgent(runner);
runnerAgent.run();
}
}
结果
代理人同意
宝贝儿跑起来...
(2)装饰模式
我们使用装饰模式在保持运动员原有功能外,加一个氮气加速功能。
IRunner与Runner的代码相同:
public interface IRunner {
public void run();
}
public class Runner implements IRunner {
@Override
public void run() {
System.out.println("宝贝儿跑起来...");
}
}
装饰类对运动员添加功能:
public class RunnerWithJet implements IRunner {
private IRunner runner;
public RunnerWithJet(IRunner runner) {
this.runner = runner;
}
@Override
public void run() {
this.runner.run();
System.out.println("启动氮气加速...");
}
}
public class Client1 {
public static void main(String[] args) {
IRunner runner = new Runner();
IRunner runnerWithJet = new RunnerWithJet(runner);
runnerWithJet.run();
}
}
结果
宝贝儿跑起来...
启动氮气加速...
有上面代码可见,代理模式和装饰模式代码几乎相同。但是,代理模式不对被被代理类的功能做任何处理,保证原汁原味的调用。装饰模式是在要保证接口不变的情况下加强类的功能。
装饰模式VS适配器模式
相同点:都是包装作用,都是通过委托方式实现其功能。
不同点:
★ 意图不同:
- 装饰模式是加强对象的功能,它不改变类的行为和属性,只是增加(当然了,减弱类的功能也是可能存在的)功能;
- 适配器模式是两个不同对象之间的转化。
★ 施与对象不同:
- 装饰模式:装饰的对象必须是自己的同宗,也就是相同的接口或父类,只要在具有相同的属性和行为的情况下,才能比较行为是增加还是减弱;
- 适配器模式:必须是两个不同的对象,因为它着重于转换,只有两个不同的对象才有转换的必要。
★ 场景不同:
- 装饰模式:在任何时候都可以使用,只要是想增强类的功能;
- 适配器模式:是一个补救模式,一般出现在系统成熟或已经构建完毕的项目中,作为一个紧急处理手段采用。
★ 扩展性不同:
- 装饰模式:很容易扩展,而且装饰类可以继续扩展下去;
- 适配器模式:在两个不同对象之间架起了一座沟通的桥梁,建立容易,去掉困难,需要从系统整体考虑是否能够撤销。
(1)装饰模式
用装饰模式来描述丑小鸭变白天鹅的过程,首先就要肯定丑小鸭是一只天鹅,然后根据时间先后来进行不同的美化处理,先长出漂亮的羽毛,然后逐步展现出异于鸭子的不同行为,如飞行,最终在具备了所有的行为后,它就成为一只纯粹的白天鹅了。
public interface Swan {
public void fly();
public void cry();
public void desAppaearance();
}
import com.sfq.impl.Swan;
public class UglyDuckling implements Swan {
@Override
public void fly() {
System.out.println("毛还没长齐,飞个毛...");
}
@Override
public void cry() {
System.out.println("声音沙哑,嘎嘎嘎...");
}
@Override
public void desAppaearance() {
System.out.println("大脑袋,大屁股,细细的脖子没有毛...");
}
}
public class Decorator implements Swan {
private Swan swan;
public Decorator(Swan swan) {
this.swan = swan;
}
@Override
public void fly() {
this.swan.fly();
}
@Override
public void cry() {
this.swan.cry();
}
@Override
public void desAppaearance() {
this.swan.desAppaearance();
}
}
import com.sfq.impl.Decorator;
import com.sfq.impl.Swan;
public class BeautifyAppearance extends Decorator {
public BeautifyAppearance(Swan swan) {
super(swan);
}
@Override
public void desAppaearance() {
System.out.println("外表纯白,很好看...");
}
}
import com.sfq.impl.Decorator;
import com.sfq.impl.Swan;
public class StrongBehavior extends Decorator {
public StrongBehavior(Swan swan) {
super(swan);
}
@Override
public void fly() {
System.out.println("会飞了...");
}
}
import com.sfq.action.BeautifyAppearance;
import com.sfq.action.StrongBehavior;
import com.sfq.action.UglyDuckling;
import com.sfq.impl.Swan;
public class Client {
public static void main(String[] args) {
System.out.println("-----从前,有只丑小鸭-----");
Swan duckling = new UglyDuckling();
duckling.desAppaearance();
duckling.cry();
duckling.fly();
System.out.println("-----后来,变成白天鹅-----");
duckling = new BeautifyAppearance(duckling);
duckling = new StrongBehavior(duckling);
duckling.desAppaearance();
duckling.cry();
duckling.fly();
}
}
结果
-----从前,有只丑小鸭-----
大脑袋,大屁股,细细的脖子没有毛...
声音沙哑,嘎嘎嘎...
毛还没长齐,飞个毛...
-----后来,变成白天鹅-----
外表纯白,很好看...
声音沙哑,嘎嘎嘎...
会飞了...
装饰模式关注了对象功能的强化,是对原始对象的行为和属性的修正和加强。
(2)适配器模式
我们使用适配器UglyDuckling,把一只白天鹅封装成了小鸭子
public interface Duck {
public void cry();
public void desAppearance();
public void desBehavior();
}
import com.sfq.impl.Duck;
public class Duckling implements Duck {
@Override
public void cry() {
System.out.println("嘎嘎嘎...");
}
@Override
public void desAppearance() {
System.out.println("黄白相间...");
}
@Override
public void desBehavior() {
System.out.println("会游泳...");
}
}
public interface Swan {
public void fly();
public void cry();
public void desAppaearance();
}
import com.sfq.impl.Swan;
public class WhiteSwan implements Swan {
@Override
public void fly() {
System.out.println("会飞...");
}
@Override
public void cry() {
System.out.println("克鲁克鲁克鲁...");
}
@Override
public void desAppaearance() {
System.out.println("纯白纯白的...");
}
}
import com.sfq.impl.Duck;
public class UglyDuckling extends WhiteSwan implements Duck {
@Override
public void cry() {
super.cry();
}
@Override
public void desAppearance() {
super.desAppaearance();
}
@Override
public void desBehavior() {
System.out.println("会游泳...");
super.fly();
}
}
import com.sfq.action.Duckling;
import com.sfq.action.UglyDuckling;
import com.sfq.impl.Duck;
public class Client {
public static void main(String[] args) {
System.out.println("-----普通鸭子-----");
Duck duck = new Duckling();
duck.cry();
duck.desAppearance();
duck.desBehavior();
System.out.println("-----丑鸭子-----");
Duck uglyDuckling = new UglyDuckling();
uglyDuckling.cry();
uglyDuckling.desAppearance();
uglyDuckling.desBehavior();
}
}
结果
-----普通鸭子-----
嘎嘎嘎...
黄白相间...
会游泳...
-----丑鸭子-----
克鲁克鲁克鲁...
纯白纯白的...
会游泳...
会飞...