一、定义
建造者模式,将一个复杂的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
二、模板方法模式结构图
角色 | 类别 | 说明 |
---|---|---|
Builder | 接口或抽象类 | 抽象的建造者,不是必须的 |
ConcreateBuilder | 具体的建造者 | 可以有多个「因为每个建造风格可能不一样」 |
Product | 普通的类 | 具体的产品「即被建造的对象」 |
Director | 导演也叫指挥者 | 统一指挥建造者去建造目标,导演不是必须的 |
三、模式的实现
public class Product {
private List<String> parts = new ArrayList<>();
public void addPart(String part) {
parts.add(part);
}
public void showProduct() {
for (String part : parts) {
System.out.println(part);
}
}
}
public abstract class Builder {
public abstract void buildPartA();
public abstract void buildPartB();
public abstract Product getResult();
}
public class ConcreteBuilderOne extends Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.addPart("部件A");
}
@Override
public void buildPartB() {
product.addPart("部件B");
}
@Override
public Product getResult() {
return product;
}
}
public class ConcreteBuilderTwo extends Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.addPart("部件A");
}
@Override
public void buildPartB() {
product.addPart("部件B");
}
@Override
public Product getResult() {
return product;
}
}
public class Director {
public void construct(Builder builder) {
builder.buildPartA();
builder.buildPartB();
}
}
public static void main(String[] args) {
Director director = new Director();
Builder builderOne = new ConcreteBuilderOne();
Builder builderTwo = new ConcreteBuilderTwo();
director.construct(builderOne);
Product p1 = builderOne.getResult();
p1.showProduct();
director.construct(builderTwo);
Product p2 = builderTwo.getResult();
p2.showProduct();
}
四、使用的案例
dubbo 源码中获取内存cache的一段逻辑就是用了建造者模式,接着直接贴上源码对照着上面的四部分。
分析:构建cache都要先缓存到一个map中去,get的时候先从map获取,获取不到,在构建,然后放入map。整个流程是固定的,只是放入的Cache有多种。
Product
public interface Cache {
void put(Object key, Object value);
Object get(Object key);
}
public class LruCache implements Cache {
private final Map<Object, Object> store;
public LruCache(String url) {
final int max = 1000;
//TODO 1 LinkedHashMap可以做成lru格式的
this.store = new LinkedHashMap<Object, Object>() {
private static final long serialVersionUID = -3834209229668463829L;
@Override
protected boolean removeEldestEntry(Entry<Object, Object> eldest) {
return size() > max;
}
};
}
@Override
public void put(Object key, Object value) {
synchronized (store) {
store.put(key, value);
}
}
@Override
public Object get(Object key) {
synchronized (store) {
return store.get(key);
}
}
}
Builder
public abstract class AbstractCacheFactory implements CacheFactory {
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
@Override
public Cache getCache(String url) {
String key = url;
Cache cache = caches.get(key);
if (cache == null) {
caches.put(key, createCache(url));
cache = caches.get(key);
}
return cache;
}
protected abstract Cache createCache(String url);
}
ConcreteBuliderOne
public class LruCacheFactory extends AbstractCacheFactory {
@Override
protected Cache createCache(String url) {
return new LruCache(url);
}
}
ConcreteBuliderTwo
public class JCacheFactory extends AbstractCacheFactory {
protected Cache createCache(URL url) {
return new JCache(url);
}
}
Director
public class Director {
public Cache construct(AbstractCacheFactory abstractCacheFactory) {
return abstractCacheFactory.getCache("cache");
}
}
public class Director {
public Cache construct(AbstractCacheFactory abstractCacheFactory) {
return abstractCacheFactory.getCache("cache");
}
}
public static void main(String[] args) {
Director director = new Director();
AbstractCacheFactory abstractCacheFactory = new LruCacheFactory();
Cache cache = director.construct(abstractCacheFactory);
}
四、建造者模式的特点
1、使创建产品的步骤「把创建产品步骤放在不同的方法中,更加清晰直观」和产品本身分离,即使用相同的创建过程要吧创建出不同的产品
2、每个建造者都是独立的互不影响,这样就达到解耦的目的,所以如果想要替换现有的建造者那非常方便,添加一个实现即可。
所以说,建造者模式实在创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式是使用的模式。