设计模式

设计模式 典型应用 框架中的应用
工厂方法 适合在单个产品上做纬度扩展  
抽象工厂 适合在产品族的纬度上扩展 bean工厂
Mediator 调节模式 消息中间件(内部之间调和)(居委会大妈) mq
Facade 门面模式 将复杂的服务整合,当用户访问后,可以通过简单的方式访问到复杂的服务(包工头)  
责任链模式 需要用状态来确定责任是否完成,通常需要用boolean来确定 Filter Interceptor,Filter中FilterChain负责调用的顺序,里面是一个递归的方法
Observer观察者 事件处理模型  
Decorator装饰器 顾名思义,就是在原来的基础上在加一层装饰,装饰的类和被装饰的类都可以横向扩展(在开发的时候,就是类在继承,而方法在嵌套) 在IO流中,比如Reader 包含InputStream
*观察者模式Observer 观察者很少和事件源打交道,主要是和事件打交道,和Listener,hook function,callback function 都是观察者 很多系统中,Observer模式往往和负责责任链共同负责对于事件的处理,其中某一个observer负责是否将事件进一步传递
组合Composite 树状结构专用模式 可用于导航栏
享元Flyweight 重复利用对象,共享元数据,有池化的概念 String 就是这个模式,使用的时候 可以和组合模式一起使用
代理模式 静态代理,动态代理,springAop,代理也实现被代理类的接口,并在代理类中将接口类作为成员变量 有点类似 Decorator
jdk实现的动态代理需要 实体类实现了接口
cglib可以对任何类进行动态代理
*Iteratror迭代器 容器,容器遍历 其实就是多态的一个应用
Visitor访问者 在结构不变的情况下动态改变对于内部元素的动作  
ASM Iteratror+Visitor+chainfresposibility  
builder 构建复杂的对象 链式编程(在类的众多参数中,你只需要其中的一些时候,使用该模式,看代码)
Adapter(Wrapper) 接口转换器 相当于插线板的转接头一样,加一层
Bridge 双纬度扩展 分离抽象和具体
Command 封装命令(doit和undo方法) 别名:Action/Transaction
Prototype原型模式/克隆模式 Object.clone() Object 自带clone模式 有浅克隆和深克隆区分
Memento备忘录 记录状态便于回滚 记录快照(瞬时状态),存盘,使用File做序列化时,使用transient 表示透明的,不需要存盘,需要存盘的都需要实现序列化接口,或者父类实现序列化接口,在网络传输中序列化通常使用google的ProtoBuf
TemplateMethod模版方法(钩子函数)    
State状态模式 根据状态决定行为  
Intepreter解析器 动态脚本解析  

记住典型的用法和类图

1

2

3

4

5

静态代理

/**
 * 问题:我想记录坦克的移动时间
 * 最简单的办法:修改代码,记录时间
 * 问题2:如果无法改变方法源码呢?
 * 用继承?
 * v05:使用代理
 * v06:代理有各种类型
 * 问题:如何实现代理的各种组合?继承?Decorator?
 * v07:代理的对象改成Movable类型-越来越像decorator了
 *
 */
public class Tank implements Movable {

    /**
     * 模拟坦克移动了一段儿时间
     */
    @Override
    public void move() {
        System.out.println("Tank moving claclacla...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        Tank t = new Tank();
        TankTimeProxy ttp = new TankTimeProxy(t);
        TankLogProxy tlp = new TankLogProxy(ttp);
        tlp.move();

//        new TankLogProxy(
//                new TankTimeProxy(
//                        new Tank()
//                )
//        ).move();
    }
}

class TankTimeProxy implements Movable {
    Movable m;

    public TankTimeProxy(Movable m) {
        this.m = m;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        m.move();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

class TankLogProxy implements Movable {
    Movable m;

    public TankLogProxy(Movable m) {
        this.m = m;
    }

    @Override
    public void move() {
        System.out.println("start moving...");
        m.move();
        long end = System.currentTimeMillis();
        System.out.println("stopped!");
    }
}

interface Movable {
    void move();
}

动态代理

/**
 * 问题:我想记录坦克的移动时间
 * 最简单的办法:修改代码,记录时间
 * 问题2:如果无法改变方法源码呢?
 * 用继承?
 * v05:使用代理
 * v06:代理有各种类型
 * 问题:如何实现代理的各种组合?继承?Decorator?
 * v07:代理的对象改成Movable类型-越来越像decorator了
 * v08:如果有stop方法需要代理...
 * 如果想让LogProxy可以重用,不仅可以代理Tank,还可以代理任何其他可以代理的类型
 * (毕竟日志记录,时间计算是很多方法都需要的东西),这时该怎么做呢?
 * 分离代理行为与被代理对象
 * 使用jdk的动态代理
 *
 * v09: 横切代码与业务逻辑代码分离 AOP
 * v10: 通过反射观察生成的代理对象
 * jdk反射生成代理必须面向接口,这是由Proxy的内部实现决定的
 */
public class Tank implements Movable {

    /**
     * 模拟坦克移动了一段儿时间
     */
    @Override
    public void move() {
        System.out.println("Tank moving claclacla...");
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Tank tank = new Tank();

        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles","true");

        Movable m = (Movable)Proxy.newProxyInstance(Tank.class.getClassLoader(),
                new Class[]{Movable.class}, //tank.class.getInterfaces()
                new TimeProxy(tank)
        );

        m.move();

    }
}

class TimeProxy implements InvocationHandler {
    Movable m;

    public TimeProxy(Movable m) {
        this.m = m;
    }

    public void before() {
        System.out.println("method start..");
    }

    public void after() {
        System.out.println("method stop..");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //Arrays.stream(proxy.getClass().getMethods()).map(Method::getName).forEach(System.out::println);

        before();
        Object o = method.invoke(m, args);
        after();
        return o;
    }

}

interface Movable {
    void move();
}

链式编程 builder模式

public class Person {
    int id;
    String name;
    int age;
    double weight;
    int score;
    Location loc;

    private Person() {}

    public static class PersonBuilder {
        Person p = new Person();

        public PersonBuilder basicInfo(int id, String name, int age) {
            p.id = id;
            p.name = name;
            p.age = age;
            return this;
        }

        public PersonBuilder weight(double weight) {
            p.weight = weight;
            return this;
        }

        public PersonBuilder score(int score) {
            p.score = score;
            return this;
        }

        public PersonBuilder loc(String street, String roomNo) {
            p.loc = new Location(street, roomNo);
            return this;
        }

        public Person build() {
            return p;
        }
    }
  public static void main(String[] args) {
        Person p = new Person.PersonBuilder()
                .basicInfo(1, "zhangsan", 18)
                //.score(20)
                .weight(200)
                //.loc("bj", "23")
                .build();
    }
}

class Location {
    String street;
    String roomNo;

    public Location(String street, String roomNo) {
        this.street = street;
        this.roomNo = roomNo;
    }
}