Java-第十八部分-设计模式-外观模式和享元模式

173 阅读3分钟

设计模式全文

外观模式

  • 案例,影院管理,家庭影院有众多设备,有观影过程,用遥控器开启各种设备
  • Facade,过程模式,定义一个高层接口,给子系统设备提供一致的界面,用来访问子系统;通过定义一个一致的接口,屏蔽子系统的细节,使调用端跟这个接口发生调用,无需关心这个子系统的内部细节
  • 将客户端和子系统进行解耦,让子系统内部的模块更易维护和扩展,更好划分访问层次 demo.png
  • HomeFacade,外观类
public class HomeFacade {
    //定义各个子系统
    private TheaterLight tl;
    private Popcorn po;
    private Stereo st;
    private Projector pr;
    private Screen sc;
    private DVDPlayer dvd;

    public HomeFacade() {
        this.tl = TheaterLight.getInstance();
        this.po = Popcorn.getInstance();
        this.st = Stereo.getInstance();
        this.pr = Projector.getInstance();
        this.sc = Screen.getInstance();
        this.dvd = DVDPlayer.getInstance();
    }
    public void ready() {
        po.on();
        po.pop();
        sc.down();
        pr.on();
        st.on();
        dvd.on();
        tl.dim();
    }
    public void play() {
        dvd.play();
    }
    public void pause() {
        dvd.pause();
    }
    public void end() {
        po.off();
        tl.bright();
        sc.up();
        pr.off();
        st.off();
        dvd.off();
    }
}
  • TheaterLight,灯光子系统
public class TheaterLight {
    private TheaterLight() {}
    private static TheaterLight instance = new TheaterLight();
    public static TheaterLight getInstance() {
        return instance;
    }
    public void on() {
        System.out.println("TheaterLight ON");
    }
    public void off() {
        System.out.println("TheaterLight OFF");
    }
    public void dim() {
        System.out.println("TheaterLight DIM");
    }
    public void bright() {
        System.out.println("TheaterLight BRIGHT");
    }
}

MyBatis源码

  • org.apache.ibatis.session包下的Configuration,包含多个工厂 image.png
  • MetaObject对象是Mybatis框架用于访问对象属性的工作类,对实例化的对象进行赋值和取值用的。目前只支持JavaBean、Collection、Map三种类型对象访问,也可以自定义其他类型
  • 其中MetaObject,使用到了三个工厂
public MetaObject newMetaObject(Object object) {
    return MetaObject.forObject(object, this.objectFactory, this.objectWrapperFactory, this.reflectorFactory);
}
  • forObject
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    return object == null ? SystemMetaObject.NULL_META_OBJECT : new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
  • MetaObject构造根据object不同,进行了不同的初始化
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    this.originalObject = object;
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;
    this.reflectorFactory = reflectorFactory;
    if (object instanceof ObjectWrapper) {
        this.objectWrapper = (ObjectWrapper)object;
    } else if (objectWrapperFactory.hasWrapperFor(object)) {
        this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    } else if (object instanceof Map) {
        this.objectWrapper = new MapWrapper(this, (Map)object);
    } else if (object instanceof Collection) {
        this.objectWrapper = new CollectionWrapper(this, (Collection)object);
    } else {
        this.objectWrapper = new BeanWrapper(this, object);
    }

}
  • 使用时用到了多个Factory,均组合到Configuration里面,使用时只需调用Configuration的方法,获取MetaObject demo2.png

享元模式

  • 案例,产品展示网站,要求大致相同,但是有多个形式
  • 通过一套代码,共享相关的代码和数据,使其资源共享
  • 共享对象模式,Flyweright Pattern,蝇量模式,通过共享技术有效支持大量细粒度的对象
  1. 常用数据库链接,连接池中都是创建好的连接对象,需要时直接拿来用,避免重复创建
  2. 能够解决重复对象的内存浪费问题,有大量相似对象,可以用缓冲池来维护
  3. 经典的应用场景是池技术,String常量池、数据库连接池、缓冲池
  • 享元模式的两个要求,细粒度和共享对象
  1. 外部状态,变化较多,对象得以依赖的一个标记,随环境变换而变化,不可共享的状态
  2. 内部状态,相对稳定,对象共享出来的信息,不会随环境变化而变化 demo.png
  • 网站设计类图 demo2.png
  • WebSite, 抽象类
public abstract class WebSite {
    protected abstract void use(User user);
}
  • ConcreteWebSite,具体的实现,type为内部状态
public class ConcreteWebSite extends WebSite{
    //共享的部分
    private String type = "";
    public ConcreteWebSite(String type) {
        this.type = type;
    }
    @Override
    protected void use(User user) {
        System.out.println("User - " + user.getName() + " type - " + type);
    }
}
  • WebSiteFactory,缓存类
public class WebSiteFactory {
    private HashMap<String, ConcreteWebSite> pool = new HashMap<>();
    //根据网站类型,返回网站,如果没有,就创建一个放入池中
    public WebSite getWebSiteCategory(String type) {
        if (!pool.containsKey(type)) {
            pool.put(type, new ConcreteWebSite(type));
        }
        return (WebSite) pool.get(type);
    }
    //总数
    public int getWebSiteCount() {
        return pool.size();
    }
}
  • User,外部状态,需要从外部传入
public class User {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Integer源码

  • Integer.valueOf(127)在[-128,127]直接从缓存池中获取,使用享元模式,效率更高
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
  • cache的初始化 image.png
  • 字符串常量池

小结

  • 系统中有大量的对象,消耗大量内存,且对象的状态大部分可以外部化,就可以使用享元模式
  • 用唯一标识码判断,如果在内存中有,就直接返回,用Map/Table存储
  • 享元模式大大减少了对象的创建,降低内存占用
  • 提高系统的复杂度,需要分离出内部状态和外部状态,外部状态需要根据个性化决定