这次我们继续接着我们的KFGStoe连锁餐厅
我们的KFG连锁餐厅在全国各地都有连锁加盟,因为各地的口味风俗差异,所以我们的KFG餐厅都是非常具有地方特色的。
用马克思主义讲,就是我们的KFG餐厅因地制宜,将KFG餐饮风格与地方特色相结合。
什么是地方特色,就是我们的KFG餐厅根据当地饮食习惯制作出符合当地饮食的料理,店面装修也具有当地的特色。
所以这个时候我们就有了北京小清新风格KFG餐厅,北京豪华风格KFG餐厅,南京小清新风格KFG餐厅,南京豪华风格KFG餐厅。
假如我们用程序代码来表示就是
class NanjingXiaoQingXinKFGStore {
private KGFFoodLine foodLine = new NanjingFoodLine();
// ...小清新风格的装饰
}
class NanjingHaoHuaKFGStore {
private KGFFoodLine foodLine = new NanjingFoodLine();
// ...豪华风格的装饰
}
class BeijingXiaoQingXinKFGStore {
private KGFFoodLine foodLine = new BeijingFoodLine();
// ...小清新风格的装饰
}
class BeijingHaoHuaKFGStore {
private KGFFoodLine foodLine = new BeijingFoodLine();
// ...豪华风格的装饰
}
这个时候问题来了,全国至少上千个城市,那么我们的 不同装修风格的 * 地方饮食 将会是一个很庞大的数字,我们是不是真的要写出这么多类来?
这种将风格与特色相互仅仅结合的设计 并不是我们想要的,我们想要的是可以扩展的。
那么怎么扩展呢?
我们只要有一类通用的KFGStore 不管我们是北京小清新风格KFG餐厅,北京豪华风格KFG餐厅,南京小清新风格KFG餐厅,南京豪华风格KFG餐厅。
它们都是KFG餐厅,它们的主要职责都是服务顾客,让顾客在店内有着良好的心情。
至此我们需要抽取店内的共性,然后离散特性。
interface KGFFoodLine {
public Food cookChip();
public Food cookHamberger();
public Food cookChicken();
}
class BeijingFoodLine implements KGFFoodLine {
@Override
public Food cookChip() {
return new Chip("Beijing Chip");
}
@Override
public Food cookHamberger() {
return new Hamburger("Beijing Hamberger");
}
@Override
public Food cookChicken() {
return new Chicken("Beijing Chicken");
}
}
class NanjingFoodLine implements KGFFoodLine {
@Override
public Food cookChip() {
return new Chip("Nanjing Chip");
}
@Override
public Food cookHamberger() {
return new Hamburger("Nanjing Hamberger");
}
@Override
public Food cookChicken() {
return new Chicken("Nanjing Chicken");
}
}
interface Cook {
public Food cook(FoodType type);
}
abstract class KFGStore implements Cook {
private KGFFoodLine foodLine;
public void setFoodLine(KGFFoodLine foodLine) {
this.foodLine = foodLine;
}
@Override
public Food cook(FoodType type) {
switch (type) {
case CHIP:
return foodLine.cookChip();
case HAMBURGER:
return foodLine.cookHamberger();
case CHICKEN:
return foodLine.cookChicken();
default:
break;
}
return null;
}
abstract public void decoratePatternDescribe();
}
class QingXinKFGStore extends KFGStore {
// ...小清新风格的装饰
@Override
public void decoratePatternDescribe() {
// TODO Auto-generated method stub
}
}
class HaoHuaKFGStore extends KFGStore {
// ...豪华风格的装饰
@Override
public void decoratePatternDescribe() {
// TODO Auto-generated method stub
}
}
解决方案:
桥连模式:将抽象部分与实现部分分离,使它们都可以独立的变化。它是一种结构性模式,又称柄体(Handle and body)模式或者接口(Interface)模式。 当一个抽象可能有多个实现时,通常用继承来协调他们。抽象类的定义对该抽象的接口。而具体的子类则用不同的方式加以实现,但是此方法有时不够灵活。继承机制将抽象部分与他的视线部分固定在一起,使得难以对抽象部分和实现部分独立地进行修改、扩充和充用。
理解桥接模式,重点需要理解如何将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化。
构建模式的组成
抽象类(Abstraction):定义抽象类的接口,维护一个指向Implementor类型对象的指针
扩充抽象类(RefinedAbstraction):扩充由Abstraction定义的接口
实现类接口(Implementor):定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲, Implementor接口仅提供基本操作,而 Abstraction则定义了基于这些基本操作的较高层次的操作。
具体实现类(ConcreteImplementor):实现Implementor接口并定义它的具体实现。
按照上述定义,我们寻找该模式的角色对应关系吧。
抽象类:KFGStore,持有一个KFGFoodLine 接口,该接口的具体实现提供不同风格的地方美食。同时定义了一个描述装饰样式的抽象方法,由子类去实现。
扩充抽象类:QingXinKFGStore,HaoHuaKFGStore。对抽象类的方法进行实现,以产生不同装修风格的餐厅。
实现类接口:KFGFoodLine,制作各种美食,提供烹制各种各样美食的基本操作,具体怎么组合,在抽象类中依据顾客的请求合理的调用foodLine.cookxxx()
具体实现:NanjingFoodLine,BeijingFoodLine。按照接口产生独特的美食。
假设 我们 原来有 4种装修 风格, 4 种 美食风格,按照原先的设计方式,那么我们将会得到 4 x 4个类。
但是改进之后 使用Bridge设计模式后, 我们只要 4 + 4个类即可。
我这里需要强调一个问题,那就是使用桥接模式的主要目的并不是减少类,而是将抽象和实现解耦,分离接口及其实现部分,提高可扩充性。
适用性
1). 你不希望在抽象和他的实现部分之间有一个固定的绑定关系,如在程序的运行时刻实现部分应该可以被选择或者切换。
2). 类的抽象以及他的视像都可以通过生成子类的方法加以扩充。这时bridge模式使你可以对不同的抽象接口和实现部分进行组合,并对他们进行扩充。
3). 对一个抽象的实现部分的修改应该对客户不产生影响,即客户的代码不需要重新编译。
4). 你想对客户完全隐藏抽象的实现部分。
5). 你想在多个实现间 共享实现,但同时要求客户并不知道这一点。
这里举spring中ClassPathApplicationContext类作为例子。
我们都知道ClassPathApplicationContext里面有个getBean方法,而这个getBean是BeanFactory接口的实现。
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
而该ClassPathApplicationContext中getBean的实现则是从其父类AbstractApplicationContext实现的。
AbstractApplicationContext:
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, requiredType);
}
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, args);
}
@Override
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType, args);
}
该父类中的getBeanFactory()实际上是从其父类中继承下来的,对其不可见,只提供了公共接口getBeanFactory()访问
实际上等同于
beanFactory.getBean()
而这里我们的具体BeanFactory实现类则是DefaultListableBeanFactory
ClassPathApplicationContext 并不是唯一的context,还有WebApplicationContext,AnnotationApplicationContext等。
所以我们这里整理一下思路,按照之前的角色划分整理:
抽象类(Abstraction): AbstractApplicationContext
扩充抽象类(RefinedAbstraction):ClassPathApplicationContext,WebApplicationContext,AnnotationApplicationContext
实现类接口(Implementor):BeanFactory。
具体实现类(ConcreteImplementor):DefaultListableBeanFactory