外观模式
- 案例,影院管理,家庭影院有众多设备,有观影过程,用遥控器开启各种设备
- Facade,过程模式,定义一个高层接口,给子系统设备提供一致的界面,用来访问子系统;通过定义一个一致的接口,屏蔽子系统的细节,使调用端跟这个接口发生调用,无需关心这个子系统的内部细节
- 将客户端和子系统进行解耦,让子系统内部的模块更易维护和扩展,更好划分访问层次

- 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()
}
}
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,包含多个工厂

- MetaObject对象是
Mybatis框架用于访问对象属性的工作类,对实例化的对象进行赋值和取值用的。目前只支持JavaBean、Collection、Map三种类型对象访问,也可以自定义其他类型
- 其中
MetaObject,使用到了三个工厂
public MetaObject newMetaObject(Object object) {
return MetaObject.forObject(object, this.objectFactory, this.objectWrapperFactory, this.reflectorFactory);
}
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

享元模式
- 案例,产品展示网站,要求大致相同,但是有多个形式
- 通过一套代码,共享相关的代码和数据,使其资源共享
- 共享对象模式,Flyweright Pattern,蝇量模式,通过共享技术有效支持大量细粒度的对象
- 常用数据库链接,连接池中都是创建好的连接对象,需要时直接拿来用,避免重复创建
- 能够解决重复对象的内存浪费问题,有大量相似对象,可以用缓冲池来维护
- 经典的应用场景是池技术,String常量池、数据库连接池、缓冲池
- 外部状态,变化较多,对象得以依赖的一个标记,随环境变换而变化,不可共享的状态
- 内部状态,相对稳定,对象共享出来的信息,不会随环境变化而变化

- 网站设计类图

- 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);
}
}
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();
}
}
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的初始化

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