zoukankan      html  css  js  c++  java
  • 设计模式之适配器模式与外观模式

    适配器模式

    适配器模式就是将一个接口转化成另一个接口。

    一个常见的例子是插头转换器

    我们知道英式插头长这样:

    而国内的插头一般是这样的

    这时候,你就需要一个转换插头了

    而适配器的工作就像是一个转换插头。你不需要从新买一个电器,也不用换一个插孔,只需要一个转换器即可。

    假设已有一个软件系统,你希望它能和新的厂商类库搭配使用,但是这个新厂商设计出来的接口,不同于旧厂商的接口。

    你不想改变现有的代码,也不能改变厂商的代码,于是你可以写一个类,将新厂商接口转成你所希望的接口。

    情景:

    首先你有一个鸭子接口(这书有毒啊啊啊这都什么破例子)

    public interface Duck {
        public void quack();
        public void fly();
    }

    有一个鸭子的子类

    // 绿头鸭
    public class MallardDuck implements Duck {
    
        @Override
        public void quack() {
            System.out.println("Quack");
        }
    
        @Override
        public void fly() {
            System.out.println("I'm flying");
        }
        
    }

    然后现在有一只火鸡

    public interface Turkey {
        public void gobble();
        public void fly();
    }
    public class WildTurkey implements Turkey {
    
        @Override
        public void gobble() {
            System.out.println("Gobble gobble");
        }
    
        @Override
        public void fly() {
            System.out.println("I'm flying a short diatance");
        }
        
    }

    因为你想要鸭子,鸭子不够用了,但是我们有火鸡,于是你决定为火鸡写一个配适器,偷偷地假装它们是鸭子。。。。

    当需要鸭子叫的时候,就让火鸡叫,当需要鸭子飞的时候,就让火鸡飞。火鸡飞的距离短,所以还要多飞几次。

    public class TurkeyAdapter implements Duck {
        Turkey turkey;
        
        public TurkeyAdapter(Turkey turkey) {
            this.turkey = turkey;
        }
        
        public void quack() {
            turkey.gobble();
        }
        
        public void fly() {
            // 火鸡飞行距离短  要连续飞五次才能对应鸭子的飞行
            for (int i = 0; i < 5; ++i) {
                turkey.fly();
            }
        }
        
    }

    然后测试一下:

    public class DuckTestDrive {
        public static void main(String[] args) {
            MallardDuck duck = new MallardDuck();
            
            WildTurkey turkey = new WildTurkey();
            Duck turkeyAdapter = new TurkeyAdapter(turkey);
            
            System.out.println("The turkey says...");
            turkey.gobble();
            turkey.fly();
            
            System.out.println("
    The Duck says...");
            testDuck(duck);
            
            System.out.println("
    The TurkeyAdapter says...");
            testDuck(turkeyAdapter);
        }
    
        private static void testDuck(Duck duck) {
            duck.quack();
            duck.fly();
        }
    }

    输出:

    The turkey says...
    Gobble gobble
    I'm flying a short diatance
    
    The Duck says...
    Quack
    I'm flying
    
    The TurkeyAdapter says...
    Gobble gobble
    I'm flying a short diatance
    I'm flying a short diatance
    I'm flying a short diatance
    I'm flying a short diatance
    I'm flying a short diatance

    我们就可以把火鸡当成鸭子了~(真·有毒。。。。

    适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

    类图:

    上面的类图表现的是“对象”适配器,还有一种适配器,被称作“类”适配器,需要多重继承才能实现,所以在Java中是不可能的。

    现实世界一个简单的适配器。

    在早期的集合实现如Vector,Stack,HashTable都实现了一个elements()的方法,该方法会返回一个Enumeration,这个接口可以逐一走过集合内的每一个元素。

    而新的集合类,使用Iterator来遍历集合。

    现在,将枚举适配到迭代器。

    import java.util.Enumeration;
    import java.util.Iterator;
    
    public class EnumerationIterator implements Iterator {
    
        Enumeration enu;
        
        public EnumerationIterator(Enumeration enu) {
            this.enu = enu;
        }
        
        @Override
        public boolean hasNext() {
            return enu.hasMoreElements();
        }
    
        @Override
        public Object next() {
            return enu.nextElement();
        }
        
        public void remove() {
            throw new UnsupportedOperationException();
        }
    
    }

    反过来也可以将迭代器适配到枚举

    import java.util.Enumeration;
    import java.util.Iterator;
    
    public class IteratorEnumeration implements Enumeration {
        Iterator iterator;
        
        public IteratorEnumeration(Iterator iterator) {
            this.iterator = iterator;
        }
    
        @Override
        public boolean hasMoreElements() {
            return iterator.hasNext();
        }
    
        @Override
        public Object nextElement() {
            return iterator.next();
        }
    }

    测试一下:

    import java.util.ArrayList;
    import java.util.Enumeration;
    import java.util.Iterator;
    
    public class ArrayListEnumTest {
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
            list.add("适");
            list.add("配");
            list.add("器");
            list.add("模");
            list.add("式");
            Iterator iterator = list.iterator();
            Enumeration ei = new IteratorEnumeration(iterator);
            showListByEnum(ei);
        }
        
        // 一些遗留的“客户代码”仍然使用依赖于枚举接口
        public static void showListByEnum(Enumeration enumeration) {
            while (enumeration.hasMoreElements()) {
                System.out.print(enumeration.nextElement());
            }
        }
    }

    外观模式

    情景:当你需要看一场电影的时候,你可能需要调灯光放屏幕打开投影机选择模式……每一次都是一样的步骤,等结束的时候,又是一系列繁琐的动作。

    如果提供一个简单的类,能够一下就完成这一系列工作就好了。

    这时就需要用外观模式,将一系列子类包装起来,提供一个简单的接口,来替代访问一系列子系统的接口。

    • 外观模式不只简化了接口,也将客户从组件的子系统中解耦。
    • 外观模式和适配器模式可以包装许多类,但外观的意图是简化接口,而适配器的意图是将接口转换成不同接口。

    原谅自己只能写一个拙劣的例子,折叠掉。。。

    package com.wenr.chapter7;
    
    public class FacadeTest {
        public static void main(String[] args) {
            A a = new A();
            B b = new B();
            C c = new C();
            Facade facade = new Facade(a, b, c);
            facade.ABC1();
            System.out.println();
            facade.ABC2();
        }
    }
    
    
    class A {
        public void a1() {
            System.out.println("a1");
        }
        public void a2() {
            System.out.println("a2");
        }
    }
    
    class B {
        public void b1() {
            System.out.println("b1");
        }
        public void b2() {
            System.out.println("b2");
        }
    }
    
    class C {
        public void c1() {
            System.out.println("c1");
        }
        public void c2() {
            System.out.println("c2");
        }
    }
    
    class Facade {
        A a;
        B b;
        C c;
        public Facade(A a, B b, C c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }
        public void ABC1() {
            a.a1();
            b.b1();
            c.c1();
        }
        public void ABC2() {
            a.a2();
            b.b2();
            c.c2();
        }
    }
    View Code

    外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

    类图:

    设计原则:最少知识原则(又称作墨忒耳法则,Law of Demeter)

    只和你的密友交谈。

    这个原则希望我们在设计中,不要让太多的类耦合在一起,免得修改系统中的一部分,会影响到其他部分。

    怎么才能避免这样?这个原则提供了一些方针:就任何对象而言,在该对象的方法内,我们只应调用属于以下范围的方法:

    • 该对象本身
    • 被当做方法的参数而传递进来的对象
    • 此方法所创建或实例化的任何对象
    • 对象的任何组件

    举个栗子:

    不使用这个原则:

    public float getTemp() {
        Thermometer thermometer = station.getThermometer();
        return thermometer.getTemperature();    
    }

    使用这个原则:

    public float getTemp() {
        return station.getTemperature();
    }

    应用此原则时,在气象站中加一个方法,用来向温度计请求温度。这可以减少我们所依赖的类的数目。

    综上:

    当需要使用一个现有的类而其接口并不符合你的需求时,就使用适配器。

    当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。

  • 相关阅读:
    开工--行胜于言
    操作系统之内存管理
    C陷阱与缺陷读书笔记(一)
    关于复杂度的一些基本的定义
    归并排序
    快速排序
    前序中序后序非递归遍历
    直接插入排序
    冒泡排序
    程序内存映像
  • 原文地址:https://www.cnblogs.com/wenruo/p/6552948.html
Copyright © 2011-2022 走看看