桥梁模式也叫桥接模式,是指将抽象和实现解耦,使得两者可以独立地变化。桥梁模式的重点是在“解耦”上,来看下下面举的例子,看看重构前和用桥梁模式重构后的区别。
假如我有两家公司,一家做房地产,一家做山寨IPOD,两家都在帮我赚钱。
重构前:
public abstract class Company {
protected void makeMoney() {
this.produce();
this.sell();
}
//制造产品
public abstract void produce();
//销售产品
public abstract void sell();
}
public class HouseCompany extends Company {
@Override
public void produce() {
System.out.println("房地产开始建造房子");
}
@Override
public void sell() {
System.out.println("房地产公司售卖房子");
}
public void makeMoney(){
super.makeMoney();
System.out.println("房地产赚大钱了");
}
}
public class IpodCompany extends Company {
@Override
public void produce() {
System.out.println("IPOD山寨公司开始制造");
}
@Override
public void sell() {
System.out.println("山寨公司开始售卖IPOD");
}
public void makeMoney(){
super.makeMoney();
System.out.println("山寨公司赚钱了");
}
}
public class Client {
public static void main(String[] args) {
//房地产公司
Company houseCompany = new HouseCompany();
houseCompany.makeMoney();
//IPOD山寨公司
Company ipodCompany = new IpodCompany();
ipodCompany.makeMoney();
}
}
这里有一个问题,就是突然有一天山寨公司不想做IPOD了,想做平板电脑了,那么produce和sell的方法就都得变更,这样子成本太大,也违反了DIP原则,这样就相当于把公司和产品强耦合在一起了。下面用桥梁模式重构一下这个功能。
重构后:
代码:
public abstract class Company {
private Product product;
public Company(Product _product){
this.product = _product;
}
public void makeMoney(){
this.produce();
this.sell();
};
public void produce(){
this.product.produce();
}
public void sell(){
this.product.sell();
}
}
public interface Product {
public void produce();
public void sell();
}
public class HouseCompany extends Company{
public HouseCompany(Product _product) {
super(_product);
}
public void makeMoney(){
super.makeMoney();
System.out.println("房地产公司赚大钱了");
}
}
public class ShanZhaiCompany extends Company{
public ShanZhaiCompany(Product _product) {
super(_product);
// TODO Auto-generated constructor stub
}
public void makeMoney(){
super.makeMoney();
System.out.println("山寨公司赚钱了");
}
}
public class HouseProd implements Product {
@Override
public void produce() {
System.out.println("开始建造房子");
}
@Override
public void sell() {
System.out.println("开始销售房子");
}
}
public class IpodProd implements Product {
@Override
public void produce() {
System.out.println("生产IPOD产品");
}
@Override
public void sell() {
System.out.println("开始销售IPOD产品");
}
}
经过重构之后,如果突然想让山寨公司转型做平板电脑,那么只需再从product派生一个平板产品类,传给山寨公司即可。这样就很好地将公司和产品解耦开来,这也正是桥梁模式的关键所在。在这个例子中,可以将公司理解为定义中的抽象,把产品理解为抽象实现,这样就能比较好理解桥梁模式的概念了。
使用场景:
- 不希望或不适用使用继承的场景,例如继承层次过度、无法更细化设计颗粒等场景,需要考虑使用桥梁模式。
- 接口或抽象类不稳定的场景。
- 重用性要求较高的场景,设计的颗粒度越细,则被重用的可能性就越大,而采用继承则受父类的限制,不可能出现太细的颗粒度。
对于继承来说,继承的有点很多,可以把公共的方法或属性抽取,父类封装共性,子类实现特性,这是继承的基本功能。但缺点就是强侵入性,父类有一个方法,子类也必须有这个方法,这是不可选择的,会带来扩展性问题。举个例子,Father类有个方法A,Son继承了这个方法,然后GradeSon也继承了这个方法,问题是突然有一天Son要重写父类的这个方法,但GradeSon又需要用到Father的这个方法,这时就带来了扩展的问题了。
对于上面的问题,桥梁模式就是这种问题的解决方法,它描述了一种弱关联关系,还是上面的例子,Father类完全可以把有可能发生变化的方法放出去,Son子类要拥有这个方法很简单,桥梁搭过去,获得这个方法,GrandSon也一样,即使Son子类不想使用这个方法了也没关系,对GrandSon不产生影响,它不是从Son中继承来的方法。