本来这次想写一写职责链模式(Chain of Responsibility)的,可是博主明天就要去学校了,今天还需要花一些时间来整理内务,所以时间不是特别多。前段时间学习了马士兵老师讲的Bridge模式,并且马老师说这个模式做一个大概的了解就行了,那么抽一点时间来做一个小小的练习。
本次练习,依旧是基于一个实际的例子,通过这个实际的例子来学习Bridge模式。
首先,什么是Bridge桥接模式?
摘自网上一段话:“‘桥接模式’所解决的问题是将两个维度的变化分离开,使它们可以独立的变化,是采用组合的方式使两个维度联系起来.该模式应用了组合的方式,这也是设计模式的一个原则—-组合优于继承.”
模拟一下环境:现在有一个餐厅Restaurant,在餐厅里面我可以点一些食物Food。对于这些Food,从温度这个角度上来说有冷菜、热菜,而对于具体的菜品来说,有黄瓜、面条等等。目前我们就模拟两个维度,温度和具体的菜品。
首先,创建一个Restaurant类,并且定义相关的成员变量与方法,如下:
public class Restaurant {
private List<Food> foods = new ArrayList<>();
public void order(Food f) {
foods.add(f);
}
public void serving() {
for(Food f : foods) {
System.out.println(f + "cooked");
}
}
}
然后,针对于不管是各种各样的菜品,我们认为都继承Food这个抽象类,于是,我们写一个Food的抽象类,如下:
public abstract class Food {
public abstract String toString();
}
好了,接下来我创建三个类(冷菜、热菜、黄瓜)ColdFood、WarmFood、Cucumber,如下:
public class ColdFood extends Food {
public String toString() {
return "ColdFood ";
}
}
public class WarmFood extends Food {
public String toString() {
return "WarmFood ";
}
}
public class Cucumber extends Food {
public String toString() {
return "Cucumber ";
}
}
Ok,接下来就是来测试我们这个基本的点菜上菜流程:
public class Main {
public static void main(String[] args) {
Restaurant r = new Restaurant();
r.order(new ColdFood());
r.order(new Cucumber());
r.serving();
}
}
输出结果没问题:
ColdFood cooked
Cucumber cooked
好了,接下来我们开始探讨一个问题,现在对于黄瓜这样一种菜品,它不是冷菜就是热菜,他完全和上面的ColdFood或者是WarmFood有重叠的地方,同时,我要想创建一个凉拌黄瓜怎么办,我是否需要重新写一个类名叫ColdCucumberFood呢?然而桥接模式就为我们提供了一个很好的解决方案。
仔细想一想,针对两个维度的情况,我们可以写出针对这两个维度的抽象类,让其中一个维度的抽象类拥有另一个维度的引用,在本例中,热菜冷菜,我们可以让定语所创建的抽象类去拥有后面名词抽象类的引用,我写一个新的抽象类名叫FoodImpl,作为Food的具体实现类,并在Food抽象类中增加这一个类的对象的引用,就像下面这样:
public abstract class Food {
protected FoodImpl fi;
public abstract String toString();
}
public abstract class FoodImpl {
public abstract String toString();
}
接下来,我让Cucumber这样的具体Food去继承FoodImpl类而不是Food类,同时修改ColdFood、WarmFood类中的构造函数如下:
public class ColdFood extends Food {
public ColdFood(FoodImpl fi) {
this.fi = fi;
}
public String toString() {
return "ColdFood " + fi.toString();
}
}
//WarmFood同理
这样一来,我就可以做两个维度类的自由组合了
public class Main {
public static void main(String[] args) {
Restaurant r = new Restaurant();
r.order(new ColdFood(new Cucumber()));
r.order(new WarmFood(new Cucumber()));
r.serving();
}
}
查看结果:
ColdFood Cucumber cooked
WarmFood Cucumber cooked
心得
在网上看到了这样一句话,觉得很适合作为本次心得体会的总结:“桥接模式就是将高维类的降维处理,将一件事物本征的东西抽象成不同的类,通过不同的类的组合描述一件事物其实这与一般的架构设计中要求的模块功能单一化的原则是一致的。”在本参观例子中,这两个维度的连接点就是Food类中的构造函数。