解决什么问题
以下两句话是从Wikipedia上抄的,我觉得总结得很到位:
- An abstraction and its implementation should be defined and extended independently from each other.
- A compile-time binding between an abstraction and its implementation should be avoided so that an implementation can be selected at run-time.
我觉得Design Patterns: Elements of Reusable Object-Oriented Software 这本书上关于Bridge模式的例子举得不是很好。我来举个例子。
我们都知道,自然界有雄性和雌性两种性别;也有幼年,中年,老年三种年龄。我们现在来定义一个人,在性别和年龄纬度下,我们可以定义出六个类,分别是:男孩(幼年雄性),女孩(幼年雌性),男人(中年雄性),女人(中年雌性),老头(老年雄性),老太(老年雌性)。类的继承关系是这样的:
这样做的问题是抽象和实现在编译期就绑定了,什么意思呢?设想一下我们想把年龄再扩展以下,搞个青年出来,那么我们又得实现两个类:男青年,女青年,这两个类编写出来的时候,它们的getAge一定返回"teenager"。我想把Age和Sex的概念,复用到其他类上,也是不可能的。它们和Person绑死了。
Bridge模式怎么解决这个问题呢?把继承的多态,化为属性的多态。把性别和年龄这两个类和Person剥离开,让它们成为Person的属性,这样我们就不用搞这么多类,我们只需要一个Person类就好了,至于我们到底要男孩还是男人,给Male和Age这两个属性赋值就好了,这就是动态决定了抽象和实现的关系。这里的抽象是Person,而实现是Male和Age。
继承可以解决多态的问题,组合也可以解决多态的问题。我们更加Prefer组合,因为组合更灵活。我们的Sex类和Age类还可以复用到 马,牛上,但是用Boy就写死了Sex, Age与Person的关系。
Bridge模式下,类的关系如下图:
代码(Java)
package com.mycompany.business.bridge; public class Person { private Age age; private Sex sex; public Person(Age age, Sex sex){ this.age = age; this.sex = sex; } public String getAge(){ return this.age.getAge(); } public String getSex(){ return this.sex.getSex(); } }
package com.mycompany.business.bridge; public interface Age { String getAge(); }
package com.mycompany.business.bridge; public interface Sex { String getSex(); }
package com.mycompany.business.bridge; public class Female implements Sex { public String getSex() { return "I am female"; } }
package com.mycompany.business.bridge; public class Male implements Sex { public String getSex() { return "I am male"; } }
package com.mycompany.business.bridge; public class Young implements Age{ public String getAge() { return "I am young"; } }
package com.mycompany.business.bridge; public class MiddleAge implements Age { public String getAge() { return "I am middle-age"; } }
package com.mycompany.business.bridge; public class Old implements Age { public String getAge() { return "I am old"; } }
package com.mycompany.business.bridge; public class BootStrap { public static void main(String[] arge){ Person person = new Person(new Young(), new Male()); System.out.println(person.getAge()); System.out.println(person.getSex()); } }