十八:享元模式(共享重复对象,分离不同对象)

定义:享元模式(英语:Flyweight Pattern)是一种软件设计模式。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。

“看定义的意思,这个模式主要是为了减少不必要的重复对象,减少内存消耗。而要做到这个的话,那么就需要把一个对象可共享的状态给封装起来,而不可能共享的状态则从外部获取。”

小左指尖不停的敲打着桌面,继续说道:“如果所有DOTA的玩家都在一台服务器上操作,那么DOTA里的英雄应该就可以使用享元模式。每一个英雄应该都是唯一的实例,而不应该是一旦有人选了一个英雄,就要实例化一个。”

“如果是传统意义上的方式,应该是这种写法。假设有一个抽象的英雄基类。”

package com.flyweight;

//抽象英雄基类
public abstract class AbstractHero {

    protected final String name;//英雄名称

    protected final String[] skills = new String[4];//每个英雄都有四个技能

    protected long hp;//血量

    protected long mp;//魔法

    public AbstractHero() {
        super();
        this.name = getName();
        initSkills();
        checkSkills();
    }

    private void checkSkills(){
        for (int i = 0; i < skills.length; i++) {
            if (skills[i] == null) {
                throw new NullPointerException();
            }
        }
    }

    //释放技能
    public void release(int index){
        if (index < 0) {
            index = 0;
        }else if (index > 3) {
            index = 3;
        }
        System.out.println(name + "释放" + skills[index]);
    } 

    //物理攻击
    public void commonAttack(){
        System.out.println(name + "进行物理攻击");
    }

    public abstract String getName();

    public abstract void initSkills();

    public long getHp() {
        return hp;
    }

    public void setHp(long hp) {
        this.hp = hp;
    }

    public long getMp() {
        return mp;
    }

    public void setMp(long mp) {
        this.mp = mp;
    }

}

“英雄可以释放技能,物理攻击等等,而且英雄是有血量和魔法量的。下面就写两个具体的英雄看一下。”

package com.flyweight;

public class Lion extends AbstractHero{

    public String getName() {
        return "恶魔巫师";
    }

    public void initSkills() {
        skills[0] = "穿刺";
        skills[1] = "妖术";
        skills[2] = "法力汲取";
        skills[3] = "死亡一指";
    }

}

package com.flyweight;

public class SF extends AbstractHero{

    public String getName() {
        return "影魔";
    }

    public void initSkills() {
        skills[0] = "毁灭阴影";
        skills[1] = "支配死灵";
        skills[2] = "魔王降临";
        skills[3] = "魂之挽歌";
    }

}

“一个恶魔巫师,一个影魔。很显然,假设现在有四个solo局,都是SF对LION,那么现在这种方式则需要实例化四个LION和四个SF。就像下面这样。”

package com.flyweight;

public class Main {

    public static void main(String[] args) {
        //假设有四个solo局,则需要创建四个lion和四个sf
        Lion lion1=new Lion();
        SF sf1 = new SF();

        Lion lion2=new Lion();
        SF sf2 = new SF();

        Lion lion3=new Lion();
        SF sf3 = new SF();

        Lion lion4=new Lion();
        SF sf4 = new SF();

        /* 以下为释放技能,物理攻击等的打架过程  */
    }

}

“这样显然是非常浪费资源啊,四个lion和四个sf其实是有很多一样的地方的。这应该就可以使用享元模式了吧。”

“不过享元模式强调内部状态和外部状态,内部状态则是可以共享的状态,外部状态则是随外部环境而变化的状态,是无法共享的状态。那么下面要做的就是将外部状态分离出来,只保留内部状态,这样的话对象的实例就可以共享了。”

“啪!”

小左打了个响指,继续说道:“对于上面DOTA英雄的简单例子来说,血量和魔法量应该是外部状态了,因为四个solo局中,每个lion和每个sf的血量和魔法量不一定是相等的,所以这两个状态是无法共享的。但是技能和名称就不一样了,它们俩应该属于内部状态,是可以共享的,因为不管是哪个solo局里的lion或者sf,它们的英雄名称和技能都是一样的。”

“这下好办了,首先应该把基类里面的血量和魔法量删掉。”

package com.flyweight;

//抽象英雄基类
public abstract class AbstractHero {

    protected final String name;//英雄名称

    protected final String[] skills = new String[4];//每个英雄都有四个技能

    public AbstractHero() {
        super();
        this.name = getName();
        initSkills();
        checkSkills();
    }

    private void checkSkills(){
        for (int i = 0; i < skills.length; i++) {
            if (skills[i] == null) {
                throw new NullPointerException();
            }
        }
    }

    //释放技能
    public void release(int index){
        if (index < 0) {
            index = 0;
        }else if (index > 3) {
            index = 3;
        }
        System.out.println(name + "释放" + skills[index]);
    } 

    //物理攻击
    public void commonAttack(){
        System.out.println(name + "进行物理攻击");
    }

    public abstract String getName();

    public abstract void initSkills();

}

“其余的两个子类应该是不用变的,下面我还需要再写一个类去组合英雄的内部状态和外部状态。”

package com.flyweight;
//用于组合英雄内部状态和外部状态的类,假设称为角色
public class Role {

    private AbstractHero hero;//角色选择的英雄

    //我们把血量和魔法量这两个外部状态从英雄里剥离出来,放到外部的角色类中
    private long hp;

    private long mp;

    public Role(AbstractHero hero) {
        super();
        this.hero = hero;
    }

    //释放技能
    public void release(int index){
        hero.release(index);
    } 

    //物理攻击
    public void commonAttack(){
        hero.commonAttack();
    }

    public long getHp() {
        return hp;
    }

    public void setHp(long hp) {
        this.hp = hp;
    }

    public long getMp() {
        return mp;
    }

    public void setMp(long mp) {
        this.mp = mp;
    }

}

“我们用角色这个类去组合英雄的内部和外部状态,下面还需要一个享元模式最重要的类,就是提供共享功能的类。”

package com.flyweight;

import java.util.HashMap;
import java.util.Map;
//提供共享功能,单例
public class HeroManager {

    private static HeroManager heroManager = new HeroManager();

    private Map<String, AbstractHero> heroMap;

    private HeroManager(){
        heroMap = new HashMap<String, AbstractHero>();
    }

    public static HeroManager getInstance(){
        return heroManager;
    }

    //该方法提供共享功能
    public AbstractHero getHero(String name){
        AbstractHero hero = heroMap.get(name);
        if (hero == null) {
            if (name.equals("恶魔巫师")) {
                hero = new Lion();
            }else if (name.equals("影魔")) {
                hero = new SF();
            }
            heroMap.put(name, hero);
        }
        return hero;
    }
}

“现在如果再来四个solo局,那么情况就和刚才不太一样了。”

package com.flyweight;

public class Main {

    public static void main(String[] args) {
        //假设有四个solo局,则使用了享元模式的情况下,其实恶魔巫师和影魔的实例各自只有一个
        HeroManager heroManager = HeroManager.getInstance();
        Role role1 = new Role(heroManager.getHero("恶魔巫师"));
        Role role2 = new Role(heroManager.getHero("影魔"));

        Role role3 = new Role(heroManager.getHero("恶魔巫师"));
        Role role4 = new Role(heroManager.getHero("影魔"));

        Role role5 = new Role(heroManager.getHero("恶魔巫师"));
        Role role6 = new Role(heroManager.getHero("影魔"));

        Role role7 = new Role(heroManager.getHero("恶魔巫师"));
        Role role8 = new Role(heroManager.getHero("影魔"));

        /* 以下为释放技能,物理攻击等的打架过程  */
    }

}

“四个solo局当中有八个角色,选了八个英雄,四个lion和四个sf,但是很明显,使用了享元模式之后,这里面的八个英雄其实只有一个lion实例和一个sf实例,这样就大大减少了英雄的实例个数。试想一下,如果同时有1000个solo局,按照之前的方式,那么会有1000个lion的实例和1000个sf的实例,而现在使用享元模式的话,依旧是只有一个lion实例和一个sf实例。”

原文地址:https://www.cnblogs.com/2019lgg/p/11097608.html

时间: 2024-11-07 05:45:58

十八:享元模式(共享重复对象,分离不同对象)的相关文章

设计模式(十)享元模式(Flyweight)-结构型

享元模式Flyweight 组合模式解决了对象时树形结构时的处理方式.当系统需要大量使用重复的对象,而这些对象要消耗很大的资源时就需要使用享元模式来解决. 单例模式,一个类只有一个唯一的对象.也就是说,不管new多少次,只需要创建这个类的一个对象,如果不采用单例模式,没new一次就会创建一个对象,这对于系统需要使用大量重复的对象,而这些对象需要消耗很大的资源时,是很不划算的,这时就需要使用享元模式. 数据库连接池就是享元模式的典型应用. 享元模式实现原理 享元模式的实现原理图 享元模式的优缺点

设计模式(十)享元模式Flyweight(结构型)

说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面向对象技术可以很好地解决系统一些灵活性或可扩展性或抽象性的问题,但在很多情况下需要在系统中增加类和对象的个数.当对象数量太多时,将导致运行代价过高,带来性能下降等问题.比如:例子1:图形应用中的图元等对象.字处理应用中的字符对象等. 2.解决方案: 享元模式(Flyweight):对象结构型模式运用

纵横之设计模式(享元模式-性能与对象访问)

声明:本系列文章内容摘自<iOS设计模式> 享元模式:运用共享技术有效地支持大量细粒度的对象. 何为享元模式 实现享元模式需要两个关键组件,通常是可共享的享元对象和保存它们的池.某种中央对象维护这个池,并从它返回适当的实例,工厂是这一角色的理想候选.它可以通过一个工厂方法,根据父类型返回各种类型的具体享元对象.其主要目的就是维护池中的享元对象,并适当的从中返回享元对象. 何时使用享元模式 1.应用程序使用很多对象: 2.在内存中保存对象会影响内存性能: 3.对象的多处持有状态(外在状态)可以放

Java设计模式(六)合成模式 享元模式

(十一)合成模式 Composite 合成模式是一组对象的组合,这些对象可以是容器对象,也可以是单对象.组对象允许包含单对象,也可以包含其他组对象,要为组合对象和单对象定义共同的行为.合成模式的意义是 保证客户端调用单对象与组合对象的一致性. class TreeNode{ private String name; private TreeNode parent; private Vector<TreeNode> children = new Vector<TreeNode>();

设计模式——享元模式详解

0. 前言 写在最前面,本人的设计模式类博文,建议先看博文前半部分的理论介绍,再看后半部分的实例分析,最后再返回来复习一遍理论介绍,这时候你就会发现我在重点处标红的用心,对于帮助你理解设计模式有奇效哦~本文原创,转载请注明出处为SEU_Calvin的博客. 春运买火车票是一件疯狂的事情,同一时刻会有大量的查票请求涌向服务器,服务器必须做出应答来满足我们的购票需求.试想,这些请求包含着大量的重复,比如从A地到B地的车票情况,如果每次都重复创建一个车票查询结果的对象,那么GC任务将非常繁重,影响性能

第13章 结构型模式—享元模式

1. 享元模式(Flyweight Pattern)的定义 (1)运用共享技术高效地支持大量细粒度的对象 ①对象内部状态:数据不变且重复出现,这部分不会随环境变化而改变,是可以共享的. ②对象外部状态:数据是变化的,会随环境变化而改变,是不可以共享的. ③所谓的享元,就是把内部状态的数据分离出来共享,通过共享享元对象,可以减少对内存的占用.把外部状态分离出来,放到外部,让应用程序在使用的时候进行维护,并在需要的时候传递给享元对象使用. ④享元模式真正缓存和共享的是享元的内部状态,而外部状态是不被

[设计模式] javascript 之 享元模式;

享元模式说明 定义:用于解决一个系统大量细粒度对象的共享问题: 关健词:分离跟共享: 说明: 享元模式分单纯(共享)享元模式,以及组合(不共享)享元模式,有共享跟不共享之分:单纯享元模式,只包含共享的状态,可共享状态是不可变,不可修改的,这是享元的内部状态:当然有外部状态就有外部状态,外部状态是可变的,不被共享,这个外部状态由客户端来管理,是可变化的:外部状态与内部状态是独立分开的,外部状态一般作为参数传入享元对象内,但不会影响内部状态的值:外部状态,一用用于获取共享的享元对象,或多或少与内部状

Java设计模式:Flyweight(享元)模式

概念定义 享元(Flyweight)模式运用共享技术高效地支持大量细粒度对象的复用. 当系统中存在大量相似或相同的对象时,有可能会造成内存溢出等问题.享元模式尝试重用现有的同类对象,如果未找到匹配的对象则创建新对象,从而减少系统中重复创建对象实例的性能和内存消耗. 享元模式将对象的信息分为两个部分:内部状态(Internal State)和外部状态(External State).内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变.外部状态是随环境改变而改变的.不可共享的

设计模式学习08:享元模式

设计模式学习08:享元模式 参考资料 https://www.jianshu.com/p/a2aa75939766 https://www.cnblogs.com/adamjwh/p/9070107.html 简介 Use sharing to support large numbers of fine-grained objects efficiently. 使用共享对象可有效地支持大量的细粒度的对象. 享元模式(Flyweight)又称为 轻量级模式,它是一种对象结构型模式. 面向对象技术可

Head First设计模式之享元模式(蝇量模式)

一.定义 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式. 享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象.我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式.由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象. 二.结构 三.实现 namespace DesignPattern