桥接模式,组合模式、门面模式

一、桥接模式
桥接模式的定义:
将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化。
桥接模式结构图:
桥接模式,组合模式、门面模式_第1张图片
桥接模式中得角色:
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同, 实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
结合实例说明:
引用一个电视遥控器的例子,对于每一个牌子的遥控器,都有相呼应的遥控器来控制,这时候我们想到的设可能是:抽象一个遥控器接口,里面有待实现的开机,关机,换频道这样一组功能方法。然后创建具体的遥控器类去继承这个接口,实现里面的方法。这样可以满足每个电视机都实现了自己的遥控器,对于新增了其他类型的 电视机,只需要添加一个派生类就可以满足新的遥控器的派生。但是哪一天,用户要求在遥控中加入一个返回上一个频道的功能时候,就需要改变抽象出来的遥控器 接口,需要向抽象类中添加一个新的方法,这样就改变了抽象类的实现。如果用户要求同时改变电视机的产品行为,和遥控器的行为方法,对于上面的设计会造成很 大的改动。使用桥接模式可以很好的解决这些问题。
使用:
1.首先抽象出电视机,提供遥控器改变的行为方法。
public abstract class TV {
    public abstract void On();
    public abstract void Off();
    public abstract void tuneChannel();
}
2.创建具体的电视机,继承自抽象电视机类:
/// 
/// 三星牌电视机,重写基类的抽象方法
/// 
public class SamsungTV extends TV {
    public void On() {
        System.out.print("三星牌电视机已经打开了");
    }

    public void Off() {
        System.out.print("三星牌电视机已经关掉了");
    }

    public void tuneChannel() {
        System.out.print("三星牌电视机换频道");
    }
}

/// 
/// 长虹牌电视机,重写基类的抽象方法
/// 提供具体的实现
/// 
public class ChangHongTV extends TV {
    public void On() {
        System.out.print("长虹牌电视机已经打开了");
    }

    public void Off() {
        System.out.print("长虹牌电视机已经关掉了");
    }

    public void tuneChannel() {
        System.out.print("长虹牌电视机换频道");
    }
}

3.然后抽象出概览中的遥控器,扮演抽象话的角色。

// 抽象概念中的遥控器,扮演抽象化角色
public abstract class RemoteControl {
    public TV implementor;

//开电视机
//这里抽象类中不再提供实现了,而是调用实现类中的实现
    public void On() {
        implementor.On();
    }

//关电视机
    public void Off() {
        implementor.Off();
    }

//换频道
    public void SetChannel() {
        implementor.tuneChannel();
    }
}

4.创建具体遥控器类:这里面,我重写了更换频道的方法,其实还可以重写其他的方法。

/// 具体遥控器类
public class ConcreteRemote extends RemoteControl {
/// 重写更换频道方法
    public void SetChannel() {
        System.out.print("重写更换频道方法");
        super.SetChannel();
    }
}

5.调用:

public class Client {
    public static void main(String[] args) {
        // 创建一个遥控器
        RemoteControl remoteControl = new ConcreteRemote();
        //长虹电视机
        remoteControl.implementor = new ChangHongTV();
        remoteControl.On();
        remoteControl.SetChannel();
        remoteControl.Off();

        // 三星牌电视机
        remoteControl.implementor = new SamsungTV();
        remoteControl.On();
        remoteControl.SetChannel();
        remoteControl.Off();
    }
}

这样接实现了桥接模式的设计,遥控器的功能实现方法不是在遥控器中去实现了,而是将实现部分用来另一个电视机类去封装它,遥控器中只包含电视机类的一个引用,通过桥接模式,我们把抽象化和实现化部分分离开了,这样可以很好应对这两方面的变化。

优点:
抽象接口与其实现解耦,期中的抽象和实现可以独立的进行扩展,不会影响到对方。
缺点:
增加了系统的复杂度。
使用场景:
  1. 如果一个系统需要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间建立静态的联系
  2. 设计要求实现化角色的任何改变不应当影响客户端,或者实现化角色的改变对客户端是完全透明的。
  3. 需要跨越多个平台的图形和窗口系统上
  4. 一个类存在两个独立变化的维度,且两个维度都需要进行扩展。



二、组合模式

组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。

桥接模式,组合模式、门面模式_第2张图片

组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。

abstract class Component {
    public abstract void add(Component c); //增加成员
    public abstract void remove(Component c); //删除成员
    public abstract Component getChild(int i); //获取成员
    public abstract void operation(); //业务方法
}
class Leaf extends Component {
    public void add(Component c) {
        //异常处理或错误提示
    }

    public void remove(Component c) {
        //异常处理或错误提示
    }

    public Component getChild(int i) {
        //异常处理或错误提示
        return null;
    }

    public void operation() {
        //叶子构件具体业务方法的实现 
    }
}

作为抽象构件类的子类,在叶子构件中需要实现在抽象构件类中声明的所有方法,包括业务方法以及管理和访问子构件的方法,但是叶子构件不能再包含子构件,因此在叶子构件中实现子构件管理和访问方法时需要提供异常处理或错误提示。当然,这无疑会给叶子构件的实现带来麻烦。


class Composite extends Component {
    private ArrayList list = new ArrayList();
    public void add(Component c) {
        list.add(c);
    }
    public void remove(Component c) {
        list.remove(c);
    }
    public Component getChild(int i) {
        return (Component)list.get(i);
    }
    public void operation() {
        //容器构件具体业务方法的实现
        //递归调用成员构件的业务方法
        for(Object obj:list) {
            ((Component)obj).operation();
        }
    }
}


在容器构件中实现了在抽象构件中声明的所有方法,既包括业务方法,也包括用于访问和管理成员子构件的方法,如add()、remove()和getChild()等方法。需要注意的是在实现具体业务方法时,由于容器构件充当的是容器角色,包含成员构件,因此它将调用其成员构件的业务方法。在组合模式结构中,由于容器构件中仍然可以包含容器构件,因此在对容器构件进行处理时需要使用递归算法,即在容器构件的operation()方法中递归调用其成员构件的operation()方法。



三、门面模式

门面模式 的典型使用场景:
通过一个简单的接口来访问一个复杂的系统;
子系统的抽象和实现是紧耦合的;
对不同层次的软件提供一个入口点;
或者 一个系统非常复杂或者是很难理解。

结构

桥接模式,组合模式、门面模式_第3张图片

Facade

facade 类对应用中的 1、2、3 这三个包进行了抽象。

Clients

那些使用 Facade Pattern 来访问包中提供的资源的对象。

例子

下面是一个抽象出来的例子,一个客户端(你)是怎样通过一个 facade(计算机)来访问一个复杂的系统(计算机的内部,比如说 CPU 和硬盘驱动器)。
// 复杂的部分
class CPU {
    public void freeze() { }
    public void jump(long position) { }
    public void execute() { }
}
class Memory {
    public void load(long position, byte[] data) { }
}

class HardDriver {
    public byte[] read(long lba, int size) { 
        return null;
    }
}

// Facade
class ComputerFacade {
    private CPU processor;
    private Memory ram;
    private HardDriver hd;

    public ComputerFacade() {
        this.processor = new CPU();
        this.ram = new Memory();
        this.hd = new HardDriver();
    }

    public void start() {
        processor.freeze();
        ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE));
        processor.jump(BOOT_ADDRESS);
        processor.execute();
    }
}

// Client
class You {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start();
    }
} 

欢迎关注我的微信公众号:

桥接模式,组合模式、门面模式_第4张图片

你可能感兴趣的:(设计模式)