问题
众所周知,我的电脑城以台式机高度定制出名,客户到店后经理都会根据客户的需求配置他所希望的电脑。在前期的时候,顾客量少,我们会给顾客提供的配置清单基本不会重复。但是呢,随着生意越来越好,顾客越来越多,出现重复配置的情况越来越多,但是呢,因为我们之前不存档,所以每次都需要给客户开一份新的一样的清单。对于经理来说,其实在这方面完全可以提高效率的。怎么提高呢?那就是我们的今天要聊的享元模式了。
简介
先总结下上面的问题:工作中会遇到大量重复的清单数据,而因为没有存档,而会导致每一次遇到清单数据时,都需要重新创建一份,无论是否曾经是否创建过。所以,显而易见的解决方式就是存档,如果出现相同清单的话,就直接复用之前的清单即可。享元模式解决的问题和思路基本上都是很好理解的,java的很多底层技术都采用了享元模式,解决了很复杂的问题。
解决问题:解决系统中大量重复对象
解决方法:使用缓存,若缓存中有的话,直接取出,没有再创建
实例:java的池技术:线程池,连接池,常量池等。常量池最常见的就是String常量池,java虚拟机为避免大量重复string保存在内存中,而是用了常量池技术。
实现
定义以需要为主的Computer
public class Computer {
private String demand;
public Computer(String demand){
this.demand = demand;
}
public void play() {
System.out.println("play computer with demand " + demand);
}
}
定义电脑缓存池
public class ComputerPool {
private ComputerPool() {
}
private static volatile ComputerPool computerPool;
public static ComputerPool getInstance() {
if (computerPool == null) {
synchronized (ComputerPool.class) {
if (computerPool == null) {
computerPool = new ComputerPool();
}
}
}
return computerPool;
}
private static HashMap<String, Computer> map = new HashMap<>();
public Computer getComputer(String demand) {
if (map.containsKey(demand)) {
System.out.println("get computer from pool");
return map.get(demand);
}
Computer computer = new Computer(demand);
map.put(demand, computer);
return computer;
}
}
定义顾客
public class Custom {
public void buy(String demand) {
Computer computer = ComputerPool.getInstance().getComputer(demand);
computer.play();
}
}
执行代码
public static void main(String[] args) {
Custom custom = new Custom();
custom.buy("game");
Custom custom1 = new Custom();
custom1.buy("design");
Custom custom2 = new Custom();
custom2.buy("game");
Custom custom3 = new Custom();
custom3.buy("design");
}
执行结果
play computer with demand game
play computer with demand design
get computer from pool
play computer with demand game
get computer from pool
play computer with demand design
简化了实现,将以需求为key,电脑作为缓存对象(配置清单作为缓存对象更贴切)。若发现用户的需求在缓存池中存在的话,则直接从缓存池中返回,而无需重新创建对象返回。以此,若在需要大量重复对象的情形下,会大量减少对象的创建,减少内存的占用,可大大提高系统性能。
总结
优点:大大减少对象的创建,降低系统的内存,使效率提高
缺点:提升了系统的复杂性(虽然我上面写的复用实现比较简单,但大家都清楚java内的线程池,常量池的实现都较为复杂,对于java开发者来说是个难啃的骨头,并且经常会在面试中被提及。这其中原因是因为池中复用缓存的对象都较为复杂,需要去分离出外部状态和内部状态)