享元模式(Flyweight)也叫‘蝇量模式‘,主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象,有匹配的对象,则直接使用
运用共享技术有效地支持大量细粒度的对象,主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建
常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率
享元模式经典的应用场景就是池技术了,String 常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式
UML类图(原理)
UML类图(案例)
说明
代码实现
public abstract class WebSite { // 享元抽象类 // 此属性为内部状态,发布的形式只有几种,新闻,博客,公众号 protected String type; public WebSite(String type) { this.type = type; } // 使用User类作为外部状态,不同的User可以发布同一形式的网站(实际使用的是同一WebSite对象)达到了对象的复用 public abstract void use(User user); } // 具体的享元类 class ConcreteWebSite extends WebSite{ // 具体的享元产品 public ConcreteWebSite(String type) { super(type); } @Override public void use(User user) { System.out.println(user.getName() + "用" + this.type + "形式发布了网站"); } }
@Data @AllArgsConstructor public class User { // WebSite的外部状态 private String name; }
public class WebSiteFactory { // 享元工厂类,内部维护享元产品池 private Map<String, WebSite> webSiteMap = new HashMap<>(); public WebSite getWebSiteCategory(String type) { if (!webSiteMap.containsKey(type)) { // 池中没有,创建新的享元产品维护到池中,返回新创建的享元产品 webSiteMap.put(type, new ConcreteWebSite(type)); } return webSiteMap.get(type); } // 获取池中享元产品的数量 public int getWebSiteCount() { return webSiteMap.size(); } }
public class Client { public static void main(String[] args) { WebSiteFactory webSiteFactory = new WebSiteFactory(); WebSite webSite1 = webSiteFactory.getWebSiteCategory("新闻"); webSite1.use(new User("张三")); WebSite webSite2 = webSiteFactory.getWebSiteCategory("博客"); webSite2.use(new User("李四")); WebSite webSite3 = webSiteFactory.getWebSiteCategory("公众号"); webSite3.use(new User("王五")); WebSite webSite4 = webSiteFactory.getWebSiteCategory("新闻"); webSite4.use(new User("王五")); System.out.println("池中享元对象的数量为:" + webSiteFactory.getWebSiteCount()); // 3 个 System.out.println(webSite1 == webSite4); // true 其实通过享元工厂获取的是同一个对象 } }
在jdk源码的Integer类中就使用到了享元模式,Integer.valueOf()方法,在-128-127之间返回的都是同一个Integer的缓存对象
public class Client { public static void main(String[] args) { // Integer类中就使用到了享元模式,Integer.valueOf()方法,在-128-127之间返回的都是同一个Integer的缓存对象 // 如果使用 valueOf 方法得到一个 Integer 实例,范围在 -128 - 127 ,执行速度比 new 快 Integer w = Integer.valueOf(127); Integer x = new Integer(127); Integer y = Integer.valueOf(127); Integer z = new Integer(127); System.out.println(w == x); // false System.out.println(w == y); // true System.out.println(x == z); // false new出来肯定不一样 在堆内存进行分配 } }
// 源码部分 public class Integer { ...... public static Integer valueOf(int i) { // 调用该方法在-128-127内就返回缓存对象,使用的享元模式 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } ...... // 静态内部类 IntegerCache private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } // 为Integer.high赋值 high = h; cache = new Integer[(high - low) + 1]; int j = low; // 循环创建Integer对象,并放入缓冲池,此处缓冲池使用的是数组 for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} } }
原文:https://www.cnblogs.com/xiaokantianse/p/14007446.html