前言
java
秋雨绵绵,周末午后,小区凉亭。
面试
李大爷:"你来了。"编程
我:"我来了。"设计模式
李大爷:"我知道你会来的!"bash
我:"我固然会来,你固然知道,不然一天前你又怎会让我走?"服务器
我目光重落,再次凝视着他,过了好久,才缓缓道:"如今一天已过去。ide
李大爷:"整整一天。"性能
我:"好长的一天。"测试
李大爷:"好短的一天。"ui
我:"虽然我明知今日必死但我不是那种等死的人。"
李大爷:"如今你的事是否已作完,你的心愿已了。"
秋雨依旧绵绵,行人寥寥。
李大爷:"出招吧!"
我:"一天前,我败在你的手下。"
李大爷淡淡道:"也许你本不应败的,只惋惜你的人太年轻,棋法却用老了。"
我:"你借我一天时光,让我去作我本身想作的事,如今一天已过去,我……"
李大爷道:"你是来送死的。"
我:"不错,我正是来送死的。"
我:"我既然来了,就已抱定必死之心。"
李大爷道:"你不想再多活一天?"
我突然仰面而笑,道:"大丈夫生于世,若不能下棋赢遍小区大爷,广场舞浪过广场大妈,快意恩仇,就算再多活一百年,也是生不如死"。
李大爷打断了个人话,冷冷道:"你本不是个多话的人,我也不是来跟你说话的,你只求速死?"
我:"是。"
李大爷长长吐出口气,闭上眼瞪,道:"请!请出手,今天仍是你先走第一步。"
什么是享元模式
为了方便理解,咱们先来看一下享元模式的两种状态:
内部状态(Intrinsic State):是存储在享元对象内部而且不会随环境改变而改变的状态,所以内部状态能够共享。
外部状态(Extrinsic State):是随环境改变而改变的、不能够共享的状态。享元对象的外部状态必须由客户端保存,并在享元对象被建立以后,在须要使用的时候再传入到享元对象内部。一个外部状态与另外一个外部状态之间是相互独立的。
如今咱们来看一下享元模式的英文定义:
Flyweight Pattern: Use sharing to support large numbers of fine-grained objects efficiently.
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少许的对象,而这些对象都很类似,状态变化很小,能够实现对象的屡次复用。因为享元模式要求可以共享的对象必须是细粒度对象,所以它又称为轻量级模式,它是一种对象结构型模式。
享元模式的四个角色
Flyweight(抽象享元类):接口或抽象类,声明公共方法,这些方法能够向外界提供对象的内部状态,设置外部状态。
ConcreteFlyweight(具体享元类):实现了抽象享元类,其实例称为享元对象。必须是可共享的,须要封装享元对象的内部状态;。
UnsharedConcreteFlyweight(非共享具体享元类):非共享的享元实现对象,并非全部的享元对象均可以共享,非共享的享元对象一般是享元对象的组合对象。
FlyweightFactory(享元工厂类):享元工厂,主要用来建立并管理共享的享元对象,并对外提供访问共享享元的接口。它针对抽象享元类编程,将各类类型的具体享元对象存储在一个享元池中,享元池通常设计为一个存储“键值对”的集合(也能够是其余类型的集合),能够结合工厂模式进行设计;当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已建立的实例或者建立一个新的实例(若是不存在的话),返回新建立的实例并将其存储在享元池中。
享元模式的UML图
代码实例
package com.weiya.mazhichu.designpatterns.flyweight;/** * <p class="detail"> * 功能:抽象享元类 * </p> * * @author Moore * @ClassName Soldier flyweight. * @Version V1.0. * @date 2019.09.03 21:06:52 */public interface SoldierFlyweight { /** * <p class="detail"> * 功能:敌军出击方法 * </p> * * @param direction : * @author Moore * @date 2019.09.03 21:06:52 */ public void attack(String direction);}复制代码
二、编写具体享元类
package com.weiya.mazhichu.designpatterns.flyweight;/** * <p class="detail"> * 功能:具体享元类 * </p> * * @author Moore * @ClassName Concrete solider flyweight. * @Version V1.0. * @date 2019.09.04 09:45:41 */public class ConcreteSoliderFlyweight implements SoldierFlyweight { // 内部状态 private String soliderType; public ConcreteSoliderFlyweight(String soliderType) { this.soliderType = soliderType; } @Override public void attack(String direction) { if("normal".equals(soliderType)){ System.out.println("普通兵加入战场"); } if("super".equals(soliderType)){ System.out.println("超级兵加入战场"); } System.out.println("出击方向:"+direction); }}复制代码
三、编写享元工厂
package com.weiya.mazhichu.designpatterns.flyweight;import java.util.HashMap;import java.util.Map;/** * <p class="detail"> * 功能:享元工厂 * </p> * * @author Moore * @ClassName Soldier fly weight factory. * @Version V1.0. * @date 2019.09.03 21:06:58 */public class SoldierFlyWeightFactory { //工厂实例 private static SoldierFlyWeightFactory INSTANCE; // 享元池 private static Map<String,SoldierFlyweight> soldierMap = new HashMap<String,SoldierFlyweight>(); private SoldierFlyWeightFactory(){ SoldierFlyweight normalSoldier = new ConcreteSoliderFlyweight("normal"); soldierMap.put("normal",normalSoldier); SoldierFlyweight superSolider = new ConcreteSoliderFlyweight("super"); soldierMap.put("super",superSolider); } /** * <p class="detail"> * 功能:获取工厂实例 * </p> * * @return soldier fly weight factory * @author Moore * @date 2019.09.03 21:07:02 */ public static SoldierFlyWeightFactory getInstance(){ if(INSTANCE == null){ INSTANCE = new SoldierFlyWeightFactory(); return INSTANCE; } return INSTANCE; } /** * <p class="detail"> * 功能:获取享元对象 * </p> * * @param soliderType : * @return soldier flyweight * @author Moore * @date 2019.09.03 21:07:02 */ public SoldierFlyweight getSolider(String soliderType){ return soldierMap.get(soliderType); } /** * <p class="detail"> * 功能:获取享元池对象数量 * </p> * * @return int * @author Moore * @date 2019.09.03 21:07:02 */ public int getSoliderSize(){ return soldierMap.size(); }}复制代码
四、客户端测试
package com.weiya.mazhichu.designpatterns.flyweight;/** * <p class="detail"> * 功能: * </p> * * @author Moore * @ClassName Honour of kings test. * @Version V1.0. * @date 2019.09.03 21:06:44 */public class HonourOfKingsTest { public static void main(String[] args) { System.out.println("敌军还有五秒到达战场!"); SoldierFlyWeightFactory factory = SoldierFlyWeightFactory.getInstance(); SoldierFlyweight soldier1 = factory.getSolider("normal"); SoldierFlyweight soldier2 = factory.getSolider("normal"); SoldierFlyweight soldier3 = factory.getSolider("normal"); soldier1.attack("上路"); soldier2.attack("中路"); soldier3.attack("下路"); System.out.println(soldier1 == soldier2); System.out.println(soldier2 == soldier3); System.out.println("--------------------------"); System.out.println("主宰已被击败!"); SoldierFlyweight soldier4 = factory.getSolider("super"); SoldierFlyweight soldier5 = factory.getSolider("super"); SoldierFlyweight soldier6 = factory.getSolider("super"); soldier4.attack("上路"); soldier5.attack("中路"); soldier6.attack("下路"); System.out.println("对方法师残血,被超级兵打死..."); System.out.println(soldier4 == soldier5); System.out.println(soldier5 == soldier6); System.out.println("--------------------------"); System.out.println("该案例一共生成对象:" + factory.getSoliderSize() + "个"); }}复制代码
查看运行结果:
享元模式扩展
单纯享元模式:在单纯享元模式中,全部的享元对象都是能够共享的,即全部抽象享元类的子类均可共享,不存在非共享具体享元类。
复合享元模式:将一些单纯享元使用组合模式加以组合,能够造成复合享元对象,这样的复合享元对象自己不能共享,可是它们能够分解成单纯享元对象,然后者则能够共享。(复合的享元对象实现了抽象享元类,它的实例就是非共享的享元实现对象)
package com.weiya.mazhichu.designpatterns.flyweight;import java.util.HashMap;import java.util.Map;/** * <p class="detail"> * 功能: 复合享元角色类(非共享享元实现对象) * </p> * * @author Moore * @ClassName Concrete composite solider flyweight. * @Version V1.0. * @date 2019.09.04 10:56:11 */public class ConcreteCompositeSoliderFlyweight implements SoldierFlyweight { private static Map<String,SoldierFlyweight> soldierMap = new HashMap<String,SoldierFlyweight>(); /** * <p class="detail"> * 功能: 增长单纯享元对象 * </p> * * @param soliderType : * @param flyweight : * @author Moore * @date 2019.09.04 10:56:11 */ public void add(String soliderType,SoldierFlyweight flyweight){ soldierMap.put(soliderType,flyweight); } /** * <p class="detail"> * 功能: flyWeights是单纯享元对象的集合,它们具备相同的外部状态extrinsicState, * 调用的时候使用循环调用单纯享元对象的attack方法 * </p> * * @param direction : * @author Moore * @date 2019.09.03 21:06:52 */ @Override public void attack(String direction) { SoldierFlyweight flyweight = null; for(String str : soldierMap.keySet()){ flyweight = soldierMap.get(str); flyweight.attack(direction); } } /** * 移除单纯享元对象. * @param soliderType */ private void remove(String soliderType) { soldierMap.remove(soliderType); }}复制代码
package com.weiya.mazhichu.designpatterns.flyweight;import java.util.HashMap;import java.util.List;import java.util.Map;/** * <p class="detail"> * 功能:享元工厂 * </p> * * @author Moore * @ClassName Soldier fly weight factory. * @Version V1.0. * @date 2019.09.03 21:06:58 */public class SoldierFlyWeightFactory { //工厂实例 private static SoldierFlyWeightFactory INSTANCE; // 享元池 private static Map<String,SoldierFlyweight> soldierMap = new HashMap<String,SoldierFlyweight>(); private SoldierFlyWeightFactory(){ SoldierFlyweight normalSoldier = new ConcreteSoliderFlyweight("normal"); soldierMap.put("normal",normalSoldier); SoldierFlyweight superSolider = new ConcreteSoliderFlyweight("super"); soldierMap.put("super",superSolider); } /** * <p class="detail"> * 功能:获取工厂实例 * </p> * * @return soldier fly weight factory * @author Moore * @date 2019.09.03 21:07:02 */ public static SoldierFlyWeightFactory getInstance(){ if(INSTANCE == null){ INSTANCE = new SoldierFlyWeightFactory(); return INSTANCE; } return INSTANCE; } /** * <p class="detail"> * 功能:获取享元对象(单纯享元工厂方法) * </p> * * @param soliderType : * @return soldier flyweight * @author Moore * @date 2019.09.03 21:07:02 */ public SoldierFlyweight getSolider(String soliderType){ return soldierMap.get(soliderType); } /** * <p class="detail"> * 功能:复合享元工厂方法 * </p> * * @param compositeSoliderTypes : * @return soldier flyweight * @author Moore * @date 2019.09.04 11:06:24 */ public SoldierFlyweight getCompositeSolider(List<String> compositeSoliderTypes){ ConcreteCompositeSoliderFlyweight compositeFlyweight = new ConcreteCompositeSoliderFlyweight(); for(String soliderType : compositeSoliderTypes){ compositeFlyweight.add(soliderType,this.getSolider(soliderType)); } return compositeFlyweight; } /** * <p class="detail"> * 功能:获取享元池对象数量 * </p> * * @return int * @author Moore * @date 2019.09.03 21:07:02 */ public int getSoliderSize(){ return soldierMap.size(); }}复制代码
package com.weiya.mazhichu.designpatterns.flyweight;import java.util.ArrayList;import java.util.List;/** * <p class="detail"> * 功能: 测试单纯享元模式和复合享元模式 * </p> * * @author Moore * @ClassName Flyweight test. * @Version V1.0. * @date 2019.09.04 11:08:51 */public class FlyweightTest { public static void main(String[] args) { SoldierFlyWeightFactory factory = SoldierFlyWeightFactory.getInstance(); String soliderType = "normal"; SoldierFlyweight soldierFlyweight1 = factory.getSolider(soliderType); SoldierFlyweight soldierFlyweight2 = factory.getSolider(soliderType); soldierFlyweight1.attack("上路"); soldierFlyweight2.attack("中路"); System.out.println("---------------------------------"); List<String> compositeSoliderType = new ArrayList<String>(); compositeSoliderType.add("normal"); compositeSoliderType.add("super"); compositeSoliderType.add("normal"); compositeSoliderType.add("super"); compositeSoliderType.add("normal"); SoldierFlyweight compositeSoliderFlyeweight1 = factory.getSolider(compositeSoliderType); SoldierFlyweight compositeSoliderFlyeweight2 = factory.getSolider(compositeSoliderType); compositeSoliderFlyeweight1.attack("上路"); compositeSoliderFlyeweight2.attack("中路"); System.out.println("---------------------------------"); System.out.println("单纯享元模式是否共享对象:" + (soldierFlyweight1 == soldierFlyweight2)); System.out.println("复合享元模式是否共享对象:" + (compositeSoliderFlyeweight1 == compositeSoliderFlyeweight2)); }}复制代码
复合享元模式中,组成复合享元对象的每一个单纯享元对象拥有本身的内部状态,而每一个单纯享元对象的外部状态都和复合享元对象的外部状态相同。因此复合享元模式能够对多个单纯享元对象设置相同的外部状态, 这也是复合享元模式的应用场景。
复合享元模式UML图
享元模式总结
系统有大量类似或者相同对象。因为这类对象的大量使用,形成内存的大量耗费。
须要缓冲池的场景,(享元池,也就是在须要屡次使用享元对象的时候)。
对象的大部分状态均可之外部化,能够将这些外部状态传入对象中。
优势
大大减小对象的建立,下降系统的内存,使效率提升。
享元模式的外部状态相对独立,并且不会影响其内部状态,从而使得享元对象能够在不一样的环境中被共享。
缺点
须要分离出外部状态和内部状态,提升了系统的复杂度。
读取享元模式的外部状态会使得运行时间稍微变长。
为了感谢您的关注和喜好,码之初为正在找工做的小伙伴悄悄的送上一批干货,后台发送”面试“关键字,便可领取随机一份面试资料,祝全部小伙伴步步高升,前程似锦!