桥接模式
一、脱藕
- 耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。
- 脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。
- 将两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改换成为弱关联。
- 桥连模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以相对独立地变化。这就是桥连模式的用意。
二·、例题:
手机都有通讯录和游戏功能,M品牌手机和N品牌手机都有通讯录的增删改查功能和游戏功能。 - 父类是‘手机品牌’,下有‘手机品牌M’ 和‘手机品牌N’ ,每个子类下各有‘通讯录’和‘游戏’ 子类。
- 父类是‘手机软件’,下有‘通讯录’ 和‘游戏’ 子类,每个子类下各有‘手机品牌M’和‘手机品牌N’。
三、紧耦合的程序演化
1.如果现在有一个N品牌的手机,它有一个小游戏,我要玩游戏,程序该如何写。
先写一个此品牌的游戏类,再用客户端调用。
package operation;
//游戏类
//N品牌手机中的游戏
class HandsetNGame
{
public void Run()
{System.out.print("运行N品牌的手机游戏");}}
public class Main{
public static void main(String[] args){
HandsetNGame game=new HandsetNGame();
game.Run();
}
}
2.现在又有一个M牌手机,也有小游戏,客户端也可以调用,如何做。
两个品牌,都有游戏,从面向对象的思想来说,应该有一个父类“手机品牌游戏”,然后让N和M牌手机游戏都继承于它,这样可以实现同样的运行方法。
package operation;
abstract class HandsetGame
{
public abstract void Run();
}
class HandsetMGame extends HandsetGame{
public void Run() {
System.out.print("运行M牌手机游戏");
}
}
class HandsetNGame extends HandsetGame{
public void Run() {
System.out.print("运行N牌手机游戏");
}
}
public class Main{
public static void main(String[] args){
HandsetNGame game=new HandsetNGame();
game.Run();
HandsetMGame game1=new HandsetMGame();
game1.Run();
}
}
3.由于手机都需要通讯录功能,于是N品牌手机和M品牌手机都增加了通讯录的增删查改功能。
package operation;
abstract class HandsetBrand
{
public abstract void Run();
}
class HandsetBrandM extends HandsetBrand{
@Override
public void Run() {
// TODO Auto-generated method stub
}
}
class HandsetBrandN extends HandsetBrand{
@Override
public void Run() {
// TODO Auto-generated method stub
}
}
class HandsetBrandMGame extends HandsetBrandM{
public void Run() {
System.out.print("运行M牌手机游戏");
}
}
class HandsetBrandNGame extends HandsetBrandN{
public void Run() {
System.out.print("运行N牌手机游戏");
}
}
class HandsetBrandMAdressList extends HandsetBrandM{
public void Run() {
System.out.print("运行M牌通讯录");
}
}
class HandsetBrandNAdressList extends HandsetBrandN{
public void Run() {
System.out.print("运行N牌通讯录");
}
}
public class Main{
public static void main(String[] args){
HandsetBrand ab;
ab=new HandsetBrandMAdressList();
ab.Run();
ab=new HandsetBrandMGame();
ab.Run();
ab=new HandsetBrandNAdressList();
ab.Run();
ab=new HandsetBrandMGame();
ab.Run();
}
}
还有一种
也不能解决
问题:
很多情况用继承会带来麻烦。
对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现。子类的实现与它的父类有非常紧密的依赖关系,父类实现中的任何变化必然会导致子类发生变化。需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。
四、合成/聚合复用原则
合成/聚合复用原则(CAPP),尽量使用合成/聚合,尽量不要使用类继承。
合成和聚合都是关联的特殊种类。聚合表示一种弱的“拥有”关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成则是一种强的“拥有”关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样。
好处是,优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。
五、松耦合程序
package operation;
abstract class HandsetSoft
{public abstract void Run();}
class HandsetGame extends HandsetSoft{
public void Run() {
System.out.print("运行手机游戏");
}
}
class HandsetAdressList extends HandsetSoft{
public void Run() {
System.out.print("运行手机通讯录");
}
}
abstract class HandsetBrand{
protected HandsetSoft soft;
public void SetHandsetSoft(HandsetSoft soft) {
this.soft=soft;
}
public abstract void Run();
}
class HandsetBrandN extends HandsetBrand{
public void Run() {soft.Run();}
}
class HandsetBrandM extends HandsetBrand{
public void Run() {soft.Run();}
}
public class Main{
public static void main(String[] args){
HandsetBrand ab;
ab=new HandsetBrandN();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAdressList());
ab.Run();
ab=new HandsetBrandM();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAdressList());
ab.Run();
}
}
六、桥接模式
桥接模式,将抽象部分与它的实现部分分离,使它们都可以独立地变化。
什么叫抽象与它的实现分离,实现指的是抽象类和它的派生类用来实现自己的对象。
按品牌分类实现的结构图
按软件分类实现结构图
由于实现模式有多种,桥接模式的核心意图就是把这些实现独立出来,让它们各自变化。
七、桥接模式基本代码
package operation;
abstract class Implementor{
public abstract void Operation();
}
class ConcreteImplementorA extends Implementor{
public void Operation() {
System.out.println("具体实现A的方法执行");
}
}
class ConcreteImplementorB extends Implementor{
public void Operation() {
System.out.println("具体实现B的方法执行");
}
}
abstract class Abstraction{
protected Implementor implementor;
public void SetImplementor(Implementor implementor) {
this.implementor=implementor;
}
public void Operation() {
implementor.Operation();
}
}
class RefinedAbstraction extends Abstraction{
public void Operation() {
implementor.Operation();
}
}
public class Main{
public static void main(String[] args){
Abstraction ab=new RefinedAbstraction();
ab.SetImplementor(new ConcreteImplementorA());
ab.Operation();
ab.SetImplementor(new ConcreteImplementorB());
ab.Operation();
}
}