设计模式一:适配器模式

  现在我们有两个类Dog和Cat,这两个类都有发出声音的功能

public class Cat {
    public void catCall() {
        System.out.println("喵!喵!喵!");
    }
}
public class Dog {
    public void dogCall() {
        System.out.println("汪!汪!汪!");
    }
}
View Code

   然后增加需求,获取动物的叫声,这时就要把这两个类的发声功能整合到一个接口:

public interface Animal {
    void call();
}
View Code

  这个很简单,直接重新设计代码,使Cat和Dog实现接口就行。但是考虑到Dog和Cat两个类来自于第三方Jar包,没有办法进行重构,就使用设配器模式,使Cat和Dog类分别统一到接口的调用!

/**Cat的设配器类  对象适配器模式!*/
public class CatAdapter implements Animal {
    Cat cat = new Cat();
    public void call() {
        cat.catCall();
    }
}
/** Dog类的设配器类  类适配器模式! */
public class DogAdapter extends Dog implements Animal {
    public void call() {
        this.dogCall();
    }
}
View Code

  这时Cat和Dog的调用:测试

/** 测试*/
public class App {
    public static void main(String[] args) {
        Animal cat = new CatAdapter();
        Animal dog = new DogAdapter();
        cat.call();
        dog.call();
    }
}
View Code

  到这里就完成了Cat和Dog的接口统一了。不过在对Cat和Dog的适配中选用的适配方式不同。CatAdapter是使用一个Cat实例实现接口函数,而DogAdaptec是继承Dog类使用父类函数实现接口函数,这两种模式分别叫做 对象的适配器模式和类的适配器模式。

设计模式二:外观模式

  现在我有2个子模块,分别是加、减

/** 加法 子模块*/
public class Plus {
    public int plus(int a, int b) {
        return a + b;
    }
}
/** 减法 子模块*/
public class Minus {
    public int minus(int a, int b) {
        return a - b;
    }
}
View Code

  那么现在客户端A想要使用上面的两个子模块实现一个 1+2-3+4的功能

/** 客户端 A*/
public class ClientA {
    public int handle() {
        Minus minus = new Minus();
        Plus plus = new Plus();
        return plus.plus(minus.minus(plus.plus(1, 2), 3), 4);
    }
}
View Code

  如果这个时候有客户端B也要实现这样的功能,甚至是1+2-3+4-5+6的功能,这时在想ClientA一样实现的话,会显得代码重复臃肿,而且当子模块间的逻辑发生变化时,会牵连到客户端A和B的模块代码改变。这时,增加一个外观类来定义一些常用的子模块操作就非常有必要了。

/** 外观类*/
public class Facade {
    public int handle(int begin, int end) {
        Minus minus = new Minus();
        Plus plus = new Plus();
        int res = begin++;
        while (begin <= end) {
            res = plus.plus(res, begin++);
            if (begin > end) break;
            res = minus.minus(res, begin++);
        }
        return res;
    }
}
View Code

  这时ClientA的代码变为

/** 客户端 A*/
public class ClientA {
    public int handle() {
        /*Minus minus = new Minus();
        Plus plus = new Plus();
        return plus.plus(minus.minus(plus.plus(1, 2), 3), 4);*/
        Facade facade = new Facade();
        return facade.handle(1, 4);
    }
}
View Code

  此时ClientA,B的重复代码减少,而且不用关注子系统的调用逻辑,只需要请求Façade类提供的调用就行,降低程序的耦合性。而当子系统有增删和逻辑变动时,需要同时更新外观类的逻辑即可。

设计模式三:组合模式

  组合模式的定义:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

  以员工的层级关系为例,现在有empA,和empB两个等级的员工,如果老板要让所有员工work,他将调用所有对象的work函数,这样老板的工作量太大,而且现实中也不会这样处理。

/** B类员工 */
public class EmpB {
    private String name;
    public EmpB(String name) {
        this.name = name;
    }
    public void work() {
        System.out.println(name + " begin work!");
    }
}
/** A员工类*/
public class EmpA {
    private String name;
    public EmpA(String name) {
        this.name = name;
    }
    public void work() {
        System.out.println(name + " begin work!");
    }
}
public class App {
    public static void main(String[] args) {
        EmpA a001 = new EmpA("001");
        EmpB b002 = new EmpB("002");
        EmpB b003 = new EmpB("003");
        //工作
        a001.work();
        b002.work();
        b003.work();
    }
}
View Code

  修改代码,让EmpA去指挥EmpB工作。

/**A员工类,管理EmpB员工*/
public class EmpA {
    private String name;
    List<EmpB> empBs = new ArrayList<EmpB>();
    public EmpA(String name) {
        this.name = name;
    }
    public void work() {
        System.out.println(name + " begin work!");
    }
    public void add(EmpB empB) {
        empBs.add(empB);
    }
}
public static void main(String[] args) {
    EmpA a001 = new EmpA("001");
    EmpB b002 = new EmpB("002");
    EmpB b003 = new EmpB("003");
    a001.add(b002);
    a001.add(b003);
    //工作
    a001.work();
    b002.work();
}
View Code

  现在老板可以直接指派001工作,不用管001这么让EmpB员工工作,也可以直接指挥002工作。

这就是简单的组合模式,在这样的情况下,老板对单个员工和一个小组的调用是一样的。

更多提升,因为,员工暴露的接口都是一致的,所以可以使用接口或者抽象类进行函数统一,比如work()或者add()。

/** 抽象类*/
public abstract class Emp {
    protected String name;
    protected List<Emp> emps = new ArrayList<Emp>();
    protected Emp(String name) {
        this.name = name;
    }
    public abstract void work();
    public abstract void add(Emp emp);
}
View Code

设计模式四:桥接模式

  公司要生产一个产品,可以向用户提供展示数据和接受修改的功能,但是这个项目人手不足,底层的数据的读写存储功能无法按时完成。

/** 具有展示数据和修改数据功能的产品 没有读写数据功能*/
public class Product {
    public String display() {
        //获取存错数据
        String msg = null;
        return msg;
    }

    public void update(String msg) {
        //先存储写数据
    }
}
View Code

  这时就想把这个读写存储功能外包给多个第三方开发,在发布任务的时候就先把自己需要的规范提出来,也就是自己要的接口,然后要求所有第三方都按照这个接口实现。

/** 接口*/
public interface DataBase {
    void write(String msg);
    String read();
}
/** 具有展示数据和修改数据功能的产品*/
public class Product {
    private DataBase dataBase;
    public Product(DataBase dataBase) {
        this.dataBase = dataBase;
    }
    public String display() {
        return dataBase.read();
    }
    public void update(String msg) {
        //先存储写数据
        dataBase.write(msg);
    }
}
View Code

  这时候第三方就根据接口进行实现。

/** A对接口的实现*/
public class DataBaseA implements DataBase {
    private String msg;
    public void write(String msg) {
        this.msg = msg;
    }
    public String read() {
        return this.msg;
    }
}
/**B对接口的实现*/
public class DataBaseB implements DataBase {
    private static String msg;
    public void write(String msg) {
        DataBaseB.msg = msg;
    }
    public String read() {
        return msg;
    }
}
View Code

这时公司就可以根据自己的需求来使用这两个第三方功能了。

/** 测试*/
public class App {
    public static void main(String[] args) {
        Product productA = new Product(new DataBaseA());
        Product productB = new Product(new DataBaseB());
        productA.update("use a");
        System.out.println(productA.display());
        productB.update("use b");
        System.out.println(productB.display());
    }
}
View Code

  这就是桥接模式。最常见的就是数据库的接口了!

  桥接模式和适配器模式一样,都是为上层调用统一api接口,不过适配器是多个底层接口存在,自下而上的设计;桥接模式的接口设计时,下层接口是抽象不存在的,是自上而下的设计。

设计模式五:责任链模式

  现在有一个日志输出接口

/** 日志输出接口*/
public interface LogPrinter {
    void log(String msg);
}
View Code

  分别实现三个级别的输出,Info,Warn,Error输出Warn消息的时候要输出Info消息,输出Error消息时同时输出Warn和Info消息。

/** 普通消息输出*/
public class InfoLogPrinter implements LogPrinter {
    public void log(String msg) {
        System.out.println("info: " + msg);
    }
}
/**警告输出*/
public class WarnLogPrinter {
    public void log(String msg) {
        System.out.println("info: " + msg);
    }
}
/** 错误消息输出*/
public class ErrorLogPrinter implements LogPrinter {
    public void log(String msg) {
        System.out.println("info: " + msg);
    }
}
View Code

构建日志打印类,提供三种级别方法的调用

/** 日志记录器*/
public class Logger {
    private LogPrinter info = new InfoLogPrinter();
    private WarnLogPrinter warn = new WarnLogPrinter();
    private ErrorLogPrinter error = new ErrorLogPrinter();
    public void info(String msg) {
        info.log(msg);
    }
    public void warn(String msg) {
        warn.log(msg);
        info(msg);
    }
    public void error(String msg) {
        error.log(msg);
        warn(msg);
    }
}
View Code

  从上面的代码可以看出,Logger包含了三个日志实例,每个实例都有可能去处理日志消息,如果处理日志的类不断增多,那么Logger会与更多的LogPrint耦合在一起。为了解决这个问题,我们使用责任链模式进行处理。

  在上面的代码进行修改:增加一个抽象类实现输出接口,并且维护责任链设计

/** 日志输出抽象类*/
public abstract class AbstractLogPrinter implements LogPrinter {
    protected static int INFO = 1;
    protected static int WARN = 2;
    protected static int ERROR = 3;
    private AbstractLogPrinter nextLogPrinter;
    protected int level;
    public void setNextLogPrinter(AbstractLogPrinter nextLogPrinter) {
        this.nextLogPrinter = nextLogPrinter;
    }
    public void printlog(int level, String msg) {
        if (this.level <= level) {
            log(msg);
        }
        if (nextLogPrinter != null) {
            nextLogPrinter.printlog(level, msg);
        }
    }
}
View Code

三种状态的对应输出类:

/**普通消息输出*/
public class InfoLogPrinter extends AbstractLogPrinter {
    public InfoLogPrinter() {
        this.level = AbstractLogPrinter.INFO;
    }
    public void log(String msg) {
        System.out.println("info: " + msg);
    }
}
/** 警告输出 */
public class WarnLogPrinter extends AbstractLogPrinter {
    public WarnLogPrinter() {
        this.level = AbstractLogPrinter.WARN;
    }

    public void log(String msg) {
        System.out.println("info: " + msg);
    }
}
/**错误消息输出*/
public class ErrorLogPrinter extends AbstractLogPrinter {
    public ErrorLogPrinter() {
        this.level = AbstractLogPrinter.ERROR;
    }
    public void log(String msg) {
        System.out.println("info: " + msg);
    }
}
View Code

  日志记录API:

/** 日志记录器*/
public class Logger {
    private AbstractLogPrinter logprint = null;
    public Logger() {
        AbstractLogPrinter info = new InfoLogPrinter();
        AbstractLogPrinter warn = new WarnLogPrinter();
        AbstractLogPrinter error = new ErrorLogPrinter();
        info.setNextLogPrinter(warn);
        warn.setNextLogPrinter(error);
        logprint = info;
    }
    public void info(String msg) {
        logprint.printlog(AbstractLogPrinter.INFO, msg);
    }
    public void warn(String msg) {
        logprint.printlog(AbstractLogPrinter.WARN, msg);
    }
    public void error(String msg) {
        logprint.printlog(AbstractLogPrinter.ERROR, msg);
        warn(msg);
    }
}
View Code

  在API实现中,只需要拥有一个日志记录器,就可以进行记录。第一个日志记录器将消息传递给下一个消息记录器。

  在Web开发中的过滤器和拦截器就采用了此类设计模式,在开发时我们只需要编写对应的逻辑类,放入处理链中即可。

设计模式六:单体模式

  单体模式指在整个JVM运行过程在中这个Class只有一个实例。

  第一步:这个Class只有一个实例,那么我们需要先私有化它的构造函数,保证外部无法实例化Class

/** 单体类*/
public final class Singleton {
    private Singleton() {
    }
}
View Code

  如果有子类的话可以使用protected,防止客户端程序调用即可。

  第二步:使用静态域维护实例,使用静态函数监控Class的实例创建

//初始化时创建(饥饿模式)
private static Singleton singleton = new Singleton();
private static Singleton getInstance() {
    return singleton;
}
//运行时创建(懒汉模式)
private volatile static Singleton singleton = null;
public static Singleton getInstance() {
    if (singleton == null) {
        singleton = new Singleton();
        return singleton;
    } else {
        return singleton;
    }
}
View Code

  第三步,实例化时初始化属性,使用方法操作属性;

private String name;
private Singleton() {
    this.name = "singleton";
}
public void updateName(String name) {
}
public String getName() {
    return name;
}
View Code

  这样一个单体类初步完成了,加上对多线程的考虑:

  将属性的操作方法同步:

public synchronized void updateName(String name) {}
public synchronized String getName() {
    return name;
}
View Code

  对应在初始化时创建函数,没有必要进行getInstance的同步。对于运行时创建,为了防止在对象为空时的多个线程访问导致多次创建,则需要在创建时同步:

public static Singleton getInstance() {
    if (singleton == null) {
        synchronized (Singleton.class) {
            if (singleton == null) {
                singleton = new Singleton();
            }
        }
    }
    return singleton;
}
View Code

  单体类和全是静态函数的类比较:1.单体类可以控制自己的初始化时机;2.(针对单例性而言)单体类可以继承和被继承而静态类不行。3.单体类可以根据需求变更为多体,具有灵活性。

  单体还有一种模式叫多例模式,分为有上限的无上限的,是单例模式的自然推广,特点是自己管理创建过程和维护创建出的实例。

设计模式七:观察者模式

  考虑到一种常见A获取数据,B对数据进行打印输出。

/** 简单实现*/
public class Simple {
    static class ClassA {
        private ClassB classB = new ClassB();
        public void getData(String data) {
            classB.print(data);
        }
    }
    static class ClassB {
        public void print(String data) {
            System.out.println(data);
        }
    }
    public static void main(String[] args) {
        ClassA classA = new ClassA();
        classA.getData("xxxx");
    }
}
View Code

 

  在上面的ClassA和ClassB中修改代码可以实现我们现在的需求,但是如果我们不断的扩展,这时C要监听A的数据,D,E ……,这会导致我们不断的修改代码。这时候就可以使用观察者模式。

  B,C,D都是消息需求者,A是被观察者,这时我们可以定义一个观察者 具有添加,移除,通知消息监听者的接口。统一监听者的接口,被观察者的数据接口

/** 观察者的接口*/
public interface Observer {
    void addListener(Listener listener);
    void removeListener(Listener listener);
    void notifyListener(String data);
}
/** 监听者接口*/
public interface Listener {
    void notified(String msg);
}
/**被观察者接口*/
public interface Subject {
    void update(String string);
}
/** 使用一个类实现观察者和被观察者接口*/
public class ObserverImp implements Observer, Subject {
    Set<Listener> listeners = new HashSet<>();
    @Override
    public void addListener(Listener listener) {
        listeners.add(listener);
    }
    @Override
    public void removeListener(Listener listener) {
        listeners.remove(listener);
    }
    @Override
    public void notifyListener(String data) {
        for (Listener listener : listeners) {
            listener.notified(data);
        }
    }
    @Override
    public void update(String string) {
        notifyListener(string);
    }
}
View Code

  测试

/** 测试 */
public class App {
    public static void main(String[] args) {
        ObserverImp sub = new ObserverImp();
        Listener lisA = (String data) -> {
            System.out.println("A  :" + data);
        };
        Listener lisB = (String data) -> {
            System.out.println("B  :" + data);
        };
        Listener lisC = (String data) -> {
            System.out.println("C  :" + data);
        };
        sub.addListener(lisA);
        sub.addListener(lisB);
        sub.addListener(lisC);
        sub.update("test1");
        sub.removeListener(lisB);
        sub.update("test2");
    }
}
View Code

  使用观察者模式后,可以使得在不修改原有基础代码,直接根据业务进行编码扩展。

设计模式八:中介模式

       现在在办公室里,有ABCDE五个员工手里各有一份数据,工作时,A需要BD的数据,C需要AE的数据,C需要…… 如果这五个员工都要到其他员工的工位上去那数据,多乱啊。放在程序中也是,几个对象直接都相互持有,耦合性太强了。在办公室里,老板可以给公式配一个助理解决问题,那我我们可以增加一个中介啊,所有的类都和中介打交道,不去持有其他对象。

/** 同事抽象类*/
public abstract class Colleague {
    private int number;
    private Mediator mediator;
    public Colleague(int data) {
        number = data;
    }
    public int getNumber() {
        return number;
    }
    public Mediator getMediator() {
        return mediator;
    }
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }
    public abstract int getData();
}
/** 中介接口*/
public interface Mediator {
    int getBC();
    int getCA();
    int getAB();
}
/** 中介实现类*/
public class MediatorImp implements Mediator {
    private Colleague A, B, C;
    public MediatorImp(Colleague A, Colleague B, Colleague C) {
        this.A = A;
        this.B = B;
        this.C = C;
    }
    @Override
    public int getBC() {
        return B.getNumber() + C.getNumber();
    }
    @Override
    public int getCA() {
        return A.getNumber() + C.getNumber();
    }
    @Override
    public int getAB() {
        return B.getNumber() + A.getNumber();
    }
}
View Code

  测试

/** 测试*/
public class App {
    public static void main(String[] args) {
        Colleague a = new Colleague(1) {
            @Override
            public int getData() {
                return getMediator().getBC();
            }
        };
        Colleague b = new Colleague(2) {
            @Override
            public int getData() {
                return getMediator().getCA();
            }
        };
        Colleague c = new Colleague(3) {
            @Override
            public int getData() {
                return getMediator().getAB();
            }
        };
        Mediator mediator = new MediatorImp(a, b, c);
        a.setMediator(mediator);
        b.setMediator(mediator);
        c.setMediator(mediator);
        System.out.println(a.getData());
        System.out.println(b.getData());
        System.out.println(c.getData());
    }
}
View Code

  使用中介模式就将几个同事类之间进行了解耦合,逻辑都交由中介类去处理。

posted on 2018-01-21 22:01  Stark_Tan  阅读(337)  评论(0编辑  收藏  举报