享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。所以其核心就是控制类中要有一个HashMap存储已经创建的对象。
以农药中的英雄为例吧:
定义英雄的通用行为
package com.zndroid.dm.FlyweightModel;
/**
* Created by luzhenyu on 2017/9/6.
*/
/**定义英雄通用的行为*/
public interface IHeroCommon {
//英雄行为:释放技能以及物理攻击
String releaseKills(int killIndex);
String commonAttack();
}
抽象出英雄通用操作
package com.zndroid.dm.FlyweightModel;
/**
* Created by luzhenyu on 2017/9/6.
*/
/**抽象英雄基类,并规则化可共享以及不可共享的部分*/
public abstract class BaseHero implements IHeroCommon {
protected String name;//英雄名字
protected String[] kills;
public BaseHero() {
kills = initKills();
name = getName();
checkKills();
}
private void checkKills() {
if (kills.length <= 0 && kills.length > 3)
return;//王者荣耀最多三个技能吧
}
//每个英雄技能以及名字不共享
public abstract String[] initKills();
public abstract String getName();
public abstract String passiveKill();//被动技能
//但是释放技能是共享,每个英雄大同小异
@Override
public String releaseKills(int killIndex) {
return name + " release " + kills[killIndex] + " + 被动 " + passiveKill() + " biu biu biu ~ ";
}
@Override
public String commonAttack() {
return name + " release 物理攻击 kua kua kua ~";
}
}
下面是具体的英雄实现
package com.zndroid.dm.FlyweightModel.impl;
import com.zndroid.dm.FlyweightModel.BaseHero;
/**
* Created by luzhenyu on 2017/9/6.
*/
public class Arthur extends BaseHero {
@Override
public String[] initKills() {
return new String[]{"誓约之盾", "回旋打击", "圣剑裁决"};
}
@Override
public String getName() {
return "亚瑟";
}
@Override
public String passiveKill() {
return "圣光守护";
}
}
package com.zndroid.dm.FlyweightModel.impl;
import com.zndroid.dm.FlyweightModel.BaseHero;
/**
* Created by luzhenyu on 2017/9/6.
*/
public class HouYi extends BaseHero {
@Override
public String[] initKills() {
return new String[]{"炙热之风", "燎原箭雨", "惩戒射击"};
}
@Override
public String getName() {
return "后羿";
}
@Override
public String passiveKill() {
return "迟缓之箭";
}
}
package com.zndroid.dm.FlyweightModel.impl;
import com.zndroid.dm.FlyweightModel.BaseHero;
/**
* Created by luzhenyu on 2017/9/6.
*/
public class ZhuGeLiang extends BaseHero {
@Override
public String[] initKills() {
return new String[]{"东风破袭", "时空穿梭", "元气弹"};
}
@Override
public String getName() {
return "诸葛亮";
}
@Override
public String passiveKill() {
return "策谋之刻";
}
}
核心在这,存储/新建英雄
package com.zndroid.dm.FlyweightModel;
import com.zndroid.dm.FlyweightModel.impl.Arthur;
import com.zndroid.dm.FlyweightModel.impl.HouYi;
import com.zndroid.dm.FlyweightModel.impl.ZhuGeLiang;
import java.util.HashMap;
/**
* Created by luzhenyu on 2017/9/6.
*/
public class HeroManager {
private HashMap<String, BaseHero> map;
private HeroManager(){
map = new HashMap<>();
}
private static HeroManager manager = new HeroManager();
public static HeroManager getManager() {
return manager;
}
public BaseHero createHero(String name) {
BaseHero hero = map.get(name);//用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象
if (null == hero) {
switch (name){
case "亚瑟":
hero = new Arthur();
break;
case "诸葛亮":
hero = new ZhuGeLiang();
break;
case "后羿":
hero = new HouYi();
break;
}
map.put(name, hero);
}
System.out.println("(这条消息请忽略:) " + name + "[" + hero.toString() + "]");
return hero;
}
}
下面创建玩家:
package com.zndroid.dm.FlyweightModel.user;
/**
* Created by luzhenyu on 2017/9/6.
*/
import com.zndroid.dm.FlyweightModel.BaseHero;
import com.zndroid.dm.FlyweightModel.impl.HouYi;
/**来表示玩家*/
public class Role {
private long MP;
private long HP;
private String niceName;
private BaseHero hero;
public long getMP() {
return MP;
}
public void setMP(long MP) {
this.MP = MP;
}
public long getHP() {
return HP;
}
public void setHP(long HP) {
this.HP = HP;
}
public String getNiceName() {
return niceName;
}
public void setNiceName(String niceName) {
this.niceName = niceName;
}
public Role(BaseHero hero) {
this.hero = hero;
}
public void releaseKill(int index) {
System.out.println(getNiceName() + " use " + hero.releaseKills(index));
}
public void releaseCommonAttack() {
System.out.println(getNiceName() + " use " + hero.commonAttack());
}
}
来看一下使用:
/**
* 享元模式
* 它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;
* 它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。
* 常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。
* 把一个对象可共享的状态给封装起来,而不可能共享的状态则从外部获取,享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象
* 用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象(用 HashMap 存储这些对象)。
* 应用实例:JAVA 中的 String,数据库中的数据池
* 使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。
* 注意事项: 1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。 2、这些类必须有一个工厂对象加以控制。
* */
//现在王者荣耀辣么火,同一个服务器辣么多人,玩同一角色的玩家也是非常多的,假如说有100个玩家玩亚瑟,那么游戏需要创建100个亚瑟
//分配给这100个玩家,如果10000个 1000000个呢? 想想就可怕, 明明就是同一个亚瑟这个英雄拿哪来这么多对象啊,多的也就是玩家,但是英雄不应该也这么多啊。
//这样同一个服务器内存肯定吃不消,因此,享元模式可以解决这个问题,不就是同一个亚瑟吗,他们的基础属性(内部,不共享)都是一样的,区别在于玩家的血量不一样(外部共享)以及
//玩家释放具体技能不一样(但是每个技能的效果亚瑟肯定都是一样的,具体释放哪个技能交给玩家决定好了)
//匹配中...
HeroManager manager = HeroManager.getManager();
/**蓝方队伍*/
//玩家1进入,并选择英雄
Role bRole1 = new Role(manager.createHero("后羿"));
bRole1.setHP(1000);
bRole1.setMP(1500);
bRole1.setNiceName("蓝队玩家1");
//玩家2进入,并选择英雄
Role bRole2 = new Role(manager.createHero("亚瑟"));
bRole2.setHP(0);
bRole2.setMP(2500);
bRole2.setNiceName("蓝队玩家2");
//玩家3进入,并选择英雄
Role bRole3 = new Role(manager.createHero("诸葛亮"));
bRole3.setHP(1500);
bRole3.setMP(2000);
bRole3.setNiceName("蓝队玩家3");
//......
/**红方队伍*/
//玩家1进入,并选择英雄
Role rRole1 = new Role(manager.createHero("后羿"));
rRole1.setHP(1000);
rRole1.setMP(1500);
rRole1.setNiceName("红队玩家1");
//玩家1进入,并选择英雄
Role rRole2 = new Role(manager.createHero("诸葛亮"));
rRole2.setHP(1500);
rRole2.setMP(2000);
rRole2.setNiceName("红队玩家2");
//玩家1进入,并选择英雄
Role rRole3 = new Role(manager.createHero("亚瑟"));
rRole3.setHP(0);
rRole3.setMP(2500);
rRole3.setNiceName("红队玩家3");
// 敌军还有5秒钟到达战场... //
// 以下是酣畅淋漓的战斗
bRole1.releaseKill(1);
bRole1.releaseCommonAttack();
rRole3.releaseKill(1);
rRole3.releaseCommonAttack();
rRole2.releaseKill(2);
bRole2.releaseCommonAttack();
bRole2.releaseKill(0);
rRole1.releaseCommonAttack();
rRole1.releaseKill(0);
bRole3.releaseKill(2);
// ACE
// 6分投吧~~~~
log("----------------我是分割线-----------------");
运行结果:
[ ======================================== ]
(这条消息请忽略:) 后羿[com.zndroid.dm.FlyweightModel.impl.HouYi@42a57993]
(这条消息请忽略:) 亚瑟[com.zndroid.dm.FlyweightModel.impl.Arthur@75b84c92]
(这条消息请忽略:) 诸葛亮[com.zndroid.dm.FlyweightModel.impl.ZhuGeLiang@6bc7c054]
(这条消息请忽略:) 后羿[com.zndroid.dm.FlyweightModel.impl.HouYi@42a57993]
(这条消息请忽略:) 诸葛亮[com.zndroid.dm.FlyweightModel.impl.ZhuGeLiang@6bc7c054]
(这条消息请忽略:) 亚瑟[com.zndroid.dm.FlyweightModel.impl.Arthur@75b84c92]
蓝队玩家1 use 后羿 release 燎原箭雨 + 被动 迟缓之箭 biu biu biu ~
蓝队玩家1 use 后羿 release 物理攻击 kua kua kua ~
红队玩家3 use 亚瑟 release 回旋打击 + 被动 圣光守护 biu biu biu ~
红队玩家3 use 亚瑟 release 物理攻击 kua kua kua ~
红队玩家2 use 诸葛亮 release 元气弹 + 被动 策谋之刻 biu biu biu ~
蓝队玩家2 use 亚瑟 release 物理攻击 kua kua kua ~
蓝队玩家2 use 亚瑟 release 誓约之盾 + 被动 圣光守护 biu biu biu ~
红队玩家1 use 后羿 release 物理攻击 kua kua kua ~
红队玩家1 use 后羿 release 炙热之风 + 被动 迟缓之箭 biu biu biu ~
蓝队玩家3 use 诸葛亮 release 元气弹 + 被动 策谋之刻 biu biu biu ~
[ ----------------我是分割线----------------- ]
[ ======================================== ]
【欢迎上码】
【微信公众号搜索 h2o2s2】