• 欢迎光临~

二、结构型模式

开发技术 开发技术 2022-11-19 次浏览

07. 适配器模式

二、结构型模式

Target:目标抽象类,此处是接口,客户需要用的特定接口;
Adapter:适配器类,关联适配者类,实现目标抽象类接口;
Adaptee:适配者类,被适配的角色,与Target不兼容的类,这个类需要适配(一般指三方类库)。
  适配者模式就是把一个类的接口(Adaptee)变换成客户端所期待的另一种接口(Target),从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作(Adapter)。

  • 模式优点:
    • 将目标类和适配者类解耦;
    • 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性;
    • 灵活性和扩展性比较好。
  • 模式缺点:
    • 类适配器缺点:
    • 一次最多只能适配一个适配者类,不能同时适配多个适配者;
    • 适配者类不能为最终类;
    • 目标抽象类只能为接口,不能为类;
  • 对象适配器缺点:
    • 在适配器中置换适配者类的某些方法比较麻烦。

代码实现:

public class Client {
    public static void main(String[] args) {
        Target target = new Adapter();
        target.request(); // adaptee正在执行...
    }
}

interface Target {
    void request();
}

class Adaptee {
    public void specificRequest() {
        System.out.println("adaptee正在执行...");
    }
}

class Adapter extends Adaptee implements Target {
    @Override
    public void request() {
        specificRequest(); // adaptee类的方法
    }
}

(1)适配器模式例题

  使用Java语言实现一个双向适配器实例,使得猫可以学狗叫,狗可以学猫抓老鼠,绘制相应类图并使用代码编程模拟。

二、结构型模式

代码实现:

public class Client {
    public static void main(String[] args) {
        Cat cat = new Adapter();
        cat.miao(); // 猫在学狗在汪...

        Dog dog = new Adapter();
        dog.action(); // 狗在学猫在抓老鼠...
    }
}

interface Cat {
    void miao();
    void catchMouse();
}

interface Dog {
    void wang();
    void action();
}

class RealCat implements Cat {

    @Override
    public void miao() {
        System.out.println("猫在喵...");
    }

    @Override
    public void catchMouse() {
        System.out.println("猫在抓老鼠...");
    }
}

class RealDog implements Dog {

    @Override
    public void wang() {
        System.out.println("狗在汪...");
    }

    @Override
    public void action() {
        System.out.println("狗在跑...");
    }
}

class Adapter implements Dog, Cat {

    private Dog dog = new RealDog();
    private Cat cat = new RealCat();

    @Override
    public void miao() {
        System.out.print("猫在学");
        dog.wang();
    }

    @Override
    public void action() {
        System.out.print("狗在学");
        cat.catchMouse();
    }

    @Override
    public void catchMouse() {
    }

    @Override
    public void wang() {
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }
}

08. 桥接模式

二、结构型模式

Abstraction类:抽象类
Implementor接口:实现类接口
RefinedAbstraction类:扩充抽象类
ConcreteImplementorA类:具体实现类A
ConcreteImplementorB类:具体实现类B
  可以把抽象类和实现类接口当成两个维度,把两个维度联合起来就是将其中一个维度的类作为一个主类(Abstraction),然后把另一个维度当做属性(Implementor)。如笔,可分为颜色、笔类型两个维度来桥接,形成黑色毛笔、白色画笔等。

  • 模式优点:
    • 分离抽象接口及其实现部分;
    • 可以取代多层继承方案,极大地减少了子类的个数;
    • 提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,不需要修改原有系统,符合开闭原则。
  • 模式缺点:
    • 会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就要针对抽象层进行设计与编程;
    • 正确识别出系统中两个独立变化的维度并不是一件容易的事情。

代码实现:

public class Client {
    public static void main(String[] args) {
        Abstraction abstraction = new RefinedAbstraction();
        // 调用第一个实现类
        abstraction.setImplementor(new ConcreteImplementorA());
        abstraction.operation();  // A执行...
        // 调用第二个实现类
        abstraction.setImplementor(new ConcreteImplementorB());
        abstraction.operation(); // B执行...
    }
}

abstract class Abstraction {
    Implementor implementor;
    
    public void setImplementor(Implementor implementor) {
        this.implementor = implementor;
    }
    
    public abstract void operation();
}

class RefinedAbstraction extends Abstraction {
    @Override
    public void operation() {
        implementor.operationImpl();
    }
}

interface Implementor {
    void operationImpl();
}

class ConcreteImplementorA implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("A执行...");
    }
}

class ConcreteImplementorB implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("B执行...");
    }
}

09. 组合模式

二、结构型模式

Component:抽象构件类,既可以代表叶子又可以代表容器,是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用户访问和管理Component子部件,Component可以是抽象类或者接口;
Leaf:叶子构件,在组合中表示叶子节点,叶子节点没有子节点;
Composite:容器构件,非叶子节点,用于存储子部件,在Component接口中实现子部件的相关操作,比如增删查改。
Client:客户类。
  组合模式适用于具有树形结构的对象,如组织机构、文件目录等。组合模式有透明组合模式和安全组合模式。上图是透明组合模式,抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 add()、remove() 及 getChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。
代码实现:

public class Client {
    public static void main(String[] args) {
        Component root = new Composite();
        Component children1 = new Composite();
        Component children2 = new Composite();
        Component leaf1 = new Leaf("leaf1");
        Component leaf2 = new Leaf("leaf2");
        root.add(children1);
        root.add(children2);
        children1.add(leaf1);
        children2.add(leaf2);
        root.operation();
    }
}

// 抽象构件
abstract class Component {
    abstract void operation();
    abstract void add(Component c);
    abstract void remove(Component c);
    abstract Component getChild(int i);
}

// 叶子构件
class Leaf extends Component {
    private String leafName;
    public Leaf(String leafName) {
        this.leafName = leafName;
    }
    @Override
    void operation() {
        System.out.println(leafName);
    }
    @Override
    void add(Component c) {
        // 空实现
    }
    @Override
    void remove(Component c) {
        // 空实现
    }
    @Override
    Component getChild(int i) {
        return null;
    }
}

// 容器构件
class Composite extends Component {
    private List<Component> children = new ArrayList();
    @Override
    void operation() {
        for (Component component : children) {
            // 若非叶子节点,递归执行
            component.operation();
        }
    }
    @Override
    void add(Component c) {
        children.add(c);
    }
    @Override
    void remove(Component c) {
        children.remove(c);
    }
    @Override
    Component getChild(int i) {
        return children.get(i);
    }
}

(1)组合模式例题

  在该教育机构的OA系统中可以给各级办公室下发公文,现采用组合模式设计该机构的结构,绘制相应的类图并编程模拟实现。在客户类中模拟下发公文。

二、结构型模式
二、结构型模式

Organization类:抽象部件类,其中只定义了叶子构件(Office)和容器构件(Department)的共有方法,即接收公文的方法;
Office类:叶子构件,叶子结点,表示教务/行政办公室,有接收公文的方法;
Department类:容器构件,非叶子部件,用于存储子部件,有增加子部件、删除子部件、发送公文、接收公文等操作。
Client类:客户类。
以上是安全组合模式。
代码实现:

public class Client {
    public static void main(String[] args) {
        Department beijing = new Department("北京总部");
        Office office1 = new Office("教务办公室1");
        Office office01 = new Office("行政办公室1");
        Department hunan = new Department("湖南分校");
        Office office2 = new Office("教务办公室2");
        Office office02 = new Office("行政办公室2");
        Department changsha = new Department("长沙教学点");
        Department yueyang = new Department("岳阳教学点");
        Office office3 = new Office("教务办公室3");
        Office office03 = new Office("行政办公室3");
        Office office4 = new Office("教务办公室4");
        Office office04 = new Office("行政办公室4");

        beijing.add(office1);
        beijing.add(hunan);
        beijing.add(office01);

        hunan.add(office2);
        hunan.add(changsha);
        hunan.add(yueyang);
        hunan.add(office02);

        changsha.add(office3);
        changsha.add(office03);

        yueyang.add(office4);
        yueyang.add(office04);

        beijing.sendMessage();
        System.out.println("------------------------------------------------------------------");
        hunan.sendMessage();
    }
}

// 抽象构件
interface Organization {
    void receiveMessage();
}

// 叶子构件
class Office implements Organization {
    private String name;

    public Office(String name) {
        this.name = name;
    }

    @Override
    public void receiveMessage() {
        System.out.println(name + "接收到公文");
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}

// 容器构件
class Department implements Organization {
    private String name;
    private List<Organization> children = new ArrayList<>();

    public Department(String name) {
        this.name = name;
    }

    @Override
    public void receiveMessage() {
        System.out.println(name + "接收到公文");
    }

    public void sendMessage() {
        for (Organization child : children) {
            if (child instanceof Office) {
                System.out.println(name + "给" + ((Office) child).getName() + "下发文件");
                child.receiveMessage();
            } else if (child instanceof Department) {
                System.out.println(name + "给" + ((Department) child).getName() + "下发文件");
                child.receiveMessage();
                ((Department) child).sendMessage();
            }
        }
    }

    public void add(Organization o) {
        children.add(o);
    }

    public void remove(Organization o) {
        children.remove(o);
    }

    public Organization getChild(int i) {
        return children.get(i);
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}

10. 装饰模式

二、结构型模式

Component类:抽象构件,给出一个抽象类(或接口),以规范准备接收附加责任或附加功能的对象
ConcreteComponent类:具体构件,定义一个将要接收附加责任或附加功能的对象
Decorator:抽象装饰类:持有一个构件(Component)对象的实例,并有一个与抽象构件一致的方法
ConcreteDecorator类:具体装饰类,负责给构件对象添加对应的新功能
  装饰者模式是动态地给一个对象添加一些额外的职责(功能),同时又不改变其结构。可以用来扩展一个类的功能,动态增加功能,动态撤销。

public class Client {
    public static void main(String[] args) {
        Component tea = new ConcreteComponent(); // 奶茶
        tea.operation(); // 一杯奶茶
        System.out.println();
        tea = new ConcreteDecoratorA(tea); // 加糖
        tea.operation(); // 一杯奶茶 + 一勺糖
        System.out.println();
        tea = new ConcreteDecoratorB(tea); // 加冰
        tea.operation(); // 一杯奶茶 + 一勺糖 + 一块冰
        System.out.println();
        tea = new ConcreteDecoratorA(tea); // 再加糖
        tea.operation(); // 一杯奶茶 + 一勺糖 + 一块冰 + 一勺糖
    }
}

// 抽象构件接口
interface Component {
    void operation();
}

// 具体构件
class ConcreteComponent implements Component {

    @Override
    public void operation() {
        System.out.print("一杯奶茶");
    }
}

// 抽象装饰类
abstract class Decorator implements Component {

    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

// 具体装饰类A
class ConcreteDecoratorA extends Decorator {

    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addBehavior();
    }

    private void addBehavior() {
        System.out.print(" + 一勺糖");
    }

}

// 具体装饰类B
class ConcreteDecoratorB extends Decorator {

    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addBehavior();
    }

    private void addBehavior() {
        System.out.print(" + 一块冰");
    }
}

11. 外观模式

二、结构型模式

GeneralSwitchFacade:外观角色
Light、Fan、Television:子系统角色
  用户通过使用一个开关(外观角色)可以一次性把灯、电扇、电视关闭。
  外观模式符合单一职责原则,将子系统之间的通信和相互关系达到最小,引入外观对象就是为子系统的访问提供了一个简单而单一的入口,也符合迪米特法则,降低客户类和子系统的耦合度。
代码实现:

public class Client {
    public static void main(String[] args) {
        GeneralSwitchFacade facade = new GeneralSwitchFacade();
        facade.on();
        facade.off();
    }
}

class GeneralSwitchFacade {
    private Light light = new Light();
    private Fan fan = new Fan();
    private Television tv = new Television();

    public void on() {
        light.on();
        fan.on();
        tv.on();
    }

    public void off() {
        light.off();
        fan.off();
        tv.off();
    }
}

class Fan {
    public void on() {
        System.out.println("电扇开启...");
    }

    public void off() {
        System.out.println("电扇关闭...");
    }
}

class Television {
    public void on() {
        System.out.println("电视开启...");
    }

    public void off() {
        System.out.println("电视关闭...");
    }
}

class Light {
    public void on() {
        System.out.println("灯开启...");
    }

    public void off() {
        System.out.println("灯关闭...");
    }
}

(1)外观模式例题

  在计算机主机(Mainframe)中,只需要按下主机的开机按钮(on(),即可调用其他硬件设备和软件的启动方法,如内存(Memory)的自检(check())、CPU的运行(run())、硬盘(HardDisk)的读取(read())、操作系统(OS)的载入(load())等,如果某一过程发生错误则计算机启动失败。使用外观模式模拟该过程,绘制类图并编程模拟实现。

二、结构型模式

外观角色:Mainframe类
子系统角色:Memory类,CPU类,HardDisk类,OS类
  Client通过Mainframe的on方法可以一次性执行开启内存的check、CPU的run、HardDisk的read、OS的load,其中若某个过程有问题就会抛异常,进行异常处理。

class Mainframe {
    Memory memory = new Memory();
    CPU cpu = new CPU();
    HardDisk hardDisk = new HardDisk();
    OS os = new OS();
    public void on() {
        try {
            memory.check();
            cpu.run();
            hardDisk.read();
            os.load();
        } catch (Exception e) {
            System.out.println("开机失败");
        }
    }
}

class Memory {
    public void check() {
        System.out.println("内存正在自检");
    }
}

class CPU {
    public void run() {
        // 模拟异常
        int i = 10 / 0;
        System.out.println("CPU正在运行");
    }
}

class HardDisk {
    public void read() {
        System.out.println("硬盘正在读取");
    }
}
class OS {
    public void load() {
        System.out.println("操作系统正在加载");
    }
}

12. 代理模式

  分为静态代理和动态代理,以下演示静态代理。

二、结构型模式

RealBBS:被代理类,里面有登录成功后能执行的权限方法,我们最终想要引用的对象
BBSProxy:代理类,Client调用的BBSProxy的function方法,该代理类根据权限来判断是否执行真正被代理类中的方法
BBS:抽象的接口,被代理类和代理类都要实现的共同接口
Client:客户类
  代理模式为其他对象提供一种代理以控制对这个对象的访问,在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

public class Client {
    public static void main(String[] args) {
        BBS user1 = new BBSProxy("张三", 0);
        user1.function();
        BBS user2 = new BBSProxy("李四",1);
        user2.function();
    }
}

interface BBS {
    void function();
}

class RealBBS implements BBS {

    @Override
    public void function() {
        System.out.println("您有访问、发帖的权限!!!");
    }
}

class BBSProxy implements BBS {
    private RealBBS realBBS = new RealBBS();
    private int permission;
    private String name;
    public BBSProxy(String name,int permission) {
        this.name = name;
        this.permission = permission;
    }
    @Override
    public void function() {
        if(permission > 0) {
            System.out.println("会员:" + name + ",您好!");
            realBBS.function();
        }else {
            System.out.println("用户:" + name + ",您没有访问权限...");
        }
    }
}
程序员灯塔
转载请注明原文链接:二、结构型模式
喜欢 (0)
违法和不良信息举报电话:022-22558618 举报邮箱:dljd@tidljd.com