【设计模式】二、结构型模式:适配器,桥接,组合,装饰,门面,享元,代理

5适配器模式

定义:将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

package com.simple.gof.adapter;

/**
 * 通过组合被适配对象并实现目标对象接口,来实现适配功能
 * 
 * @author chaozai
 * @date 2018年8月21日
 *
 */
public class AdapteeAdapter implements Target {

    Adaptee adaptee;

    public AdapteeAdapter(Adaptee adaptee) {
	this.adaptee = adaptee;
    }

    /**
     * 根据log的类型
     */
    @Override
    public void save(String type, String log) {
	if ("json".equals(type)) {
	    adaptee.saveLogWithJson(log);
	} else if ("xml".equals(type)) {
	    adaptee.saveLogWithXml(log);
	}
    }

}

使用场景:两个异构系统的对接模块,如C与Java,windows与linux

6桥接(桥梁)模式

定义:将抽象和实现解耦,使得两者可以独立地变化。

抽象化角色

package com.simple.gof.bridge;

/**
 * 抽象化角色
 * 
 * @author chaozai
 * @date 2018年8月21日
 *
 */
public abstract class Abstraction {
    protected Implementor implementor;

    protected Abstraction(Implementor implementor) {
	this.implementor = implementor;
    }
    
    public abstract void doSomething();
}

实现化角色

package com.simple.gof.bridge;

/**
 * 实现化角色
 * 
 * @author chaozai
 * @date 2018年8月21日
 *
 */
public interface Implementor {
    public void doSomething();
}

总结:实现化角色相当于API,API的实现可能有多种变化,此时,把实现分离,可以避免抽象化结构随实现的拓展而变化。

使用场景:当类有多层继承时,可以考虑将实现和抽象分离

7组合(树组)模式

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

package com.simple.gof.composite;

import java.util.ArrayList;
/**
 * 树形混合组件
 * @author chaozai
 * @date 2018年8月21日
 *
 */
public class Composite implements Component {
    // 子节点集合
    private ArrayList<Component> children = new ArrayList<Component>();

    @Override
    public void add(Component component) {
	children.add(component);
    }

    @Override
    public void remove(Component component) {
	children.remove(component);
    }
    
    @Override
    public ArrayList<Component> getChildren() {
	return children;
    }

}

使用场景:树形结构对象,如树形菜单,文件和文件夹

8装饰者模式

定义:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

package com.simple.gof.decorator;

/**
 * 抽象装饰者实现被装饰接口
 * 
 * @author chaozai
 * @date 2018年8月21日
 *
 */
public abstract class Decorator implements Component {
    protected Component component;

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

    @Override
    public void doSomething() {
	component.doSomething();
	//添加装饰行为
	this.doDecorate();
    }
    /**
     * 装饰行为,可以选择集成在doSomething被装饰行为之中,也可以配合模板模型使用
     */
    public abstract void doDecorate();
}

使用场景:需要动态扩展一个类的功能,或给一个类增加附加功能

9外观(门面)模式

定义:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

package com.simple.gof.facade;

/**
 * 门面对象
 * </p>
 * 客户端直接沟通门面对象,无感知门面之内的对象
 * </p>
 * 区分于适配器:适配器存在三个对象(适配器,目标对象,被适配对象),客户端直接使用目标对象;而门面模式客户端直接使用门面
 * @author chaozai
 * @date 2018年8月21日
 *
 */
public class Facade {
    Component component;
    /**
     * 客户端无感知component子类存在,在内部构造
     */
    public Facade() {
	component = new Component() {
	    @Override
	    public void methodC() {
	    }

	    @Override
	    public void methodB() {
	    }

	    @Override
	    public void methodA() {
	    }
	};
    }
    /**
     * 对外部暴露方法,方法内组合复杂处理方式
     */
    public void method(){
	component.methodA();
	component.methodB();
	component.methodC();
    }
}

总结:门面就是门面,外部需求是使用门面,而适配器是归属目标对象,外部需求是使用目标对象。

使用场景: 为一个复杂的模块或子系统提供一个供外界访问的接口

10享元模式

定义:使用共享对象可有效地支持大量的细粒度的对象。

package com.simple.gof.flyweight;

import java.util.HashMap;

/**
 * 享元工厂
 * </p>
 * 需要考虑线程安全问题
 * @author chaozai
 * @date 2018年8月21日
 *
 */
public class FlyweightFactory {

    private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();

    /**
     * 获取享元对象
     * 
     * @param extrinsic 外部状态
     * @return
     */
    public static Flyweight getFlyweight(String extrinsic) {
	Flyweight flyweight = null;
	if (pool.containsKey(extrinsic)) {
	    flyweight = pool.get(extrinsic);
	} else {
	    // 实际应用需要根据外部状态来创建对应的实例对象
	    flyweight = new Flyweight() {
	    };
	    pool.put(extrinsic, flyweight);
	}
	return flyweight;
    }
}

总结:注意线程安全问题;能够减少重复对象创建

使用场景:大量相似对象,且存在外部状态;需要缓冲池;java常用对象缓存

11代理模式

定义:为其他对象提供一种代理以控制对这个对象的访问。

普通代理:调用者只知代理而不用知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响

package com.simple.gof.proxy;

/**
 * 代理主题
 * 
 * @author chaozai
 * @date 2018年8月21日
 *
 */
public class Proxy implements Subject {

    private Subject subject;

    public Proxy() {
    }

    @Override
    public void doSomething() {
	if (subject == null) {
	    subject = new RealSubject();
	}
	subject.doSomething();
    }

}

动态代理:根据被代理的接口生成所有的方法

package com.simple.gof.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.simple.gof.proxy.RealSubject;
import com.simple.gof.proxy.Subject;

/**
 * 动态代理
 * 
 * @author chaozai
 * @date 2018年8月21日
 *
 * @param <T>
 *            代理对象
 */
public class DynamicProxy<T> implements InvocationHandler {

    T subject;

    public DynamicProxy(T subject) {
	this.subject = subject;
    }

    /**
     * proxy:动态代理对象,属于被代理对象 method:执行的方法 args:调用目标方法时传入的实参
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	System.out.println("start execute method: " + method.getName());
	Object result = method.invoke(subject, args);
	System.out.println("end");
	return result;
    }

    public static void main(String[] args) {
	//被代理对象
	Subject subject = new RealSubject();
	InvocationHandler invocationHandler = new DynamicProxy<Subject>(subject);
	//代理对象
	Subject proxy = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),
		new Class<?>[] { Subject.class }, invocationHandler);
	// true==getClass().getName() + '@' + Integer.toHexString(hashCode())
	System.out.println("subject.toString().equals(proxy.toString()): "
		+subject.toString().equals(proxy.toString()));
	System.out.println("subject.equals(proxy): "+subject.equals(proxy));// false
	proxy.doSomething();
    }

}

动态代理运行结果

start execute method: toString
end
subject.toString().equals(proxy.toString()): true
subject.equals(proxy): false
start execute method: doSomething
real subject do something
end

总结:装饰者是为了增加功能,而代理模式是为了对已有功能进行控制

使用场景:AOP,面向切面编程;RPC,远程方法调用

样例源码地址:https://github.com/qqchaozai/gof.git


爱家人,爱生活,爱设计,爱编程,拥抱精彩人生!

猜你喜欢

转载自blog.csdn.net/qqchaozai/article/details/81902486