一、介绍
享元模式,英文(Flyweight),这个翻译还是比较OK的。网上解释比较多,也比较抽象,用我的话来说这个模式就是一个公共,共享的区域,里面放了一些大家可以共用的对象。因为我们知道,创建对象是需要花费时间,占用内存的,但是有些对象常常不需要那么多,仅仅需要一个,或者多个就足够了,也就是不需要到哪儿使用就开始创建。上面解释有点像单例模式,其实单例也是享元 特殊的一种,都是为了复用对象,减少开销儿存在,至于区别,后面说。
二、实例分析:
2.1 这里用设计模式里面 字母的例子:我们知道英文里面有26的字母,而我们每一个字母都假设是一个对象,那么我们需要写一篇文章,肯定会使用很多字母,不可能new 很多对象吧,内存消耗不起。这时你会怎么做呢?
2.2 再来一个案例:我们现在到餐馆吃饭,,会给你一个菜单,然后通过一个 点菜器,要吃什么菜,选择了之后就传输到后台了,过一会到时候菜就送上来了。当我们后台看到A,B,C三个人,假设都点了鱼香肉丝这个菜的时候,那么我们就可以一次抄起来,3个人都用的一个对象(实际情况有点区别),这里怎么实现的呢?
先简单看看代码设计吧:
a. 首先我们要定义一个行为,点菜的行为,我称为享元行为,也就是说大家都要用的一种行为。
/** * * 设计一个抽象类,规定我们的行为 * */ public abstract class Flyweight { public abstract void dianCai(); }
b. 然后对行为具体化,也就是后台如何炒菜。我们要通过菜名才产生对象,因此要一个属性name,并强制
要求点菜,必须传入name.(不然谁知道你点的什么菜!凭啥产生对象)
/** * * 实现主要的行为,这里我们会得到具体的菜 * */ public class FlyweightImpl extends Flyweight{ // 通过菜名,获取不同的菜(对象) private String name; public FlyweightImpl(String name){ this.name = name; } @Override public void dianCai() { // 这里的行为,假设仅仅是打印 System.out.println("点的菜名是:"+name); } }
c.上面可以根据name产生对象了,但是我们需要知道A B C 三个人,到底点的什么菜呢,是否3个人都点了一样的菜呢?因此我们需要一个集合对象,来保存顾客点的什么菜,从而觉得 是抄一份呢,还是抄多份,相当于判断 都点的不同的菜,产生不同的对象,还是点的相同的菜,只需要产生一个对象。这里肯定根据菜名菜判断啦。
import java.util.HashMap; import java.util.Map; /** * * 炒菜工厂,相当于厨房 * */ public class FlyweightFactory { // 一个简单的单例 private FlyweightFactory(){} public static FlyweightFactory factory = new FlyweightFactory(); // 这个用来统一管理客户点的菜,可以从集合中判断哪些菜,被点过了 private Map<String,FlyweightImpl> map = new HashMap<String, FlyweightImpl>(); // 获得菜的对象,传入用户名字 public FlyweightImpl getCai(String name){ FlyweightImpl cai = null; // 判断是否有人点过了 if(map.containsKey(name)){ // 如果已经有人点了,那么只要炒成一份就行了 cai = map.get(name); }else{ // 如果没有,就再抄一份,并记录下来 map.put(name, cai); } return cai; } // 计算一共抄了好多份菜,产生了好多个对象 public int getSize(){ return map.size(); } }
d.下面进行测试
/** * * 客人点菜 * */ public class Client { public static void main(String[] args) { List<Flyweight> list = new ArrayList<Flyweight>(); // 这假设是用户 a b c d e f在 某个是时间点 ,点的菜 FlyweightFactory chufang = FlyweightFactory.factory; Flyweight a = chufang.getCai("鱼香肉丝"); Flyweight b = chufang.getCai("鱼香肉丝"); Flyweight c = chufang.getCai("鱼香肉丝"); Flyweight d = chufang.getCai("小白菜"); Flyweight e = chufang.getCai("小白菜"); Flyweight f = chufang.getCai("红烧肉"); list.add(a);list.add(b);list.add(c); list.add(d);list.add(e);list.add(f); // 比较对象 System.out.println(a.equals(b)); System.out.println(a.equals(c)); System.out.println(a.equals(e)); System.out.println(d.equals(e)); System.out.println(d.equals(f)); System.out.println("一共产生的对象:"+chufang.getSize()); // for(Flyweight fly : list){ fly.dianCai(); } } }
输出信息:
true true false true false 一共产生的对象:3 上的菜是:鱼香肉丝 上的菜是:鱼香肉丝 上的菜是:鱼香肉丝 上的菜是:小白菜 上的菜是:小白菜 上的菜是:红烧肉
从上面看到,虽然点了 7到菜,但是除开一样的,其实只产生了3个对象。
像字母那个实例,也许有的人会说,可以建立26个 对象,都用单例,那么也是可行的。但是如果像下面这个点菜的模式,不同的菜品,不可能创建不同的对象吧,那就太多了。
三、代码分析
享元模式,主要是为了产生对象,并管理对象,让重复对象提升利用率,减少类存开销。这里有一个很好的例子:“活字印刷术”,相信这个大家想象一下就明白。
享元模式的使用场景,相信也有一定了解了,从代码上来讲:
1、享元模式 要分为内部外部状态。
内部状态:也就是对象是根据 内部的参数而创建或者区分。比如几个引用的对象是否是同一个呢?我们可以通过对象的主键ID 进行比较,也可以通过里面集合属性(name+id) 进行比较,判断 这个对象是否一样,参考对象equals()方法。比如上面例子就是通过菜名字(name) 进行区分,创建对象的时候也是通过name 进行创建。这样的对象创建出来,name 就无法更改了,无法更改的东西,我们就是内部状态,判断该对象是否共享(已经存在),都要经过这个内部状态来判断。
外部状态:就是外部可以改变的,简单来说,假设对象已经创建了,A B C 都拿到这个对象,那么就可以对立面的属性就行改变,因为这个对象是共享的,因此一般都是发生在客户端,拿到对象之后。
上面例子,我们虽然点 鱼香肉丝的 有3个人,但是我想知道是哪些人点了,怎么办呢?我们尝试加一个可以改变的外部属性。
/** * * 设计一个抽象类,规定我们的行为 * */ public abstract class Flyweight { public abstract void dianCai(); // 添加一个 添加名字的方法 public abstract void addPerson(String name); // 获得外部属性的方法 public abstract List getPersons(); }
/** * * 实现主要的行为,这里我们会得到具体的菜 * */ public class FlyweightImpl extends Flyweight{ // 通过菜名,获取不同的菜(对象) private String name; public FlyweightImpl(String name){ this.name = name; } @Override public void dianCai() { // 这里的行为,假设仅仅是打印 System.out.println("上的菜是:"+name); } // 外部属性,存放那些人点了这些菜 private List<String> persons = new ArrayList<String>(); @Override public void addPerson(String name) { persons.add(name); } }
Test FlyweightFactory chufang = FlyweightFactory.factory; Flyweight a = chufang.getCai("鱼香肉丝"); a.addPerson("A"); Flyweight b = chufang.getCai("鱼香肉丝"); b.addPerson("B"); Flyweight c = chufang.getCai("鱼香肉丝"); c.addPerson("C"); System.out.println(Arrays.toString(a.getPersons().toArray()));
从上面可以看出,内部状态负责创建对象,如果需要其他的外部状态,是可以从新定义的。而我们熟悉的连接池 就是使用了享元模式。它根据url,driver,username,password内部属性, 创建一个可以共享的对象,然后创建的对象本身可以 断开连接等其他额外的操作,这些都是获得对象之后,在外部操作的。后面我们可以写一个简单的数据库连接池。
小结:
享元模式 为了减少重复对象,提高对象利用率,减少内存开销存在。
1.首先用抽象类或者接口 指定产生这个对象的行为。如:dianCai();
2.写一个具体的实现类,实现上面的行为,当让也可以存放一些外部状态属性
3.需要一个工厂,用来获得对象,并对产生的对象进行管理
4.客户端利用工厂,和传入的参数,而获得对象,如果有外部状态,并可以改变它。
其他:这个模式一般和 单例 工厂模式一起用。这里没加线程控制,仅仅写了享元模式的过程。单例 模式和享元模式的区别在于,单例仅仅是产生不重复的对象,而享元模式会根据内部状态来产生不重复的对象,更加灵活。
相关推荐
java常用设计模式-享元模式
设计模式-享元模式 设计模式是软件设计中的一种解决方案,旨在提高代码的可维护性、灵活性和可重用性。享元模式(Flyweight Pattern)是结构型模式的一种,主要用于减少大量相似对象的内存占用,提高系统的性能和...
享元模式是一种结构型设计模式,它通过共享已有对象来减少内存中对象的数量,从而达到降低系统内存占用、提高性能的目的。在软件工程中,当系统中存在大量相似或重复的对象时,享元模式尤为适用。 享元模式的核心是...
JAVA-设计模式-结构型模式-享元模式
设计模式--享元模式
c++设计模式-结构型模式-享元模式;qt工程;c++简单源码; 享元(Flyweight)模式的定义:运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类...
享元模式是一种优化资源使用的软件设计模式,尤其适用于对象创建成本较高或系统内存有限的场景。在Java编程中,享元模式通过共享已有对象来减少内存中的对象数量,从而提高性能。这种模式的核心是实现细粒度对象的...
Flyweight:享元对象IntrinsicState:内部状态,享元对象共享内部状态ExtrinsicState:外部状态,每个享元对象的外部状态不同pub
享元模式是一种软件设计模式,它的主要目的是为了提高性能,减少对象的创建,尤其是在大量相似对象需要被创建的情况下。在给定的咖啡店案例中,享元模式的应用可以帮助优化内存使用,避免为每杯咖啡的配料表分配独立...
设计模式通常分为三类:创建型模式(如工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式),结构型模式(如适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式、享元模式)以及行为型模式(如...
Java中的享元设计模式对于优化内存使用和提高应用程序性能至关重要。通过最小化创建的对象数量,它显著减少了内存占用。享元模式的主要目标是在相似对象之间尽可能多地共享数据,从而提高效率和性能。 ## 二、详细...
根据给定文件内容,以下是关于Java设计模式的知识点说明: 1. 策略模式(Strategy Pattern)是一种行为设计模式,允许在运行时选择算法的行为。策略模式的意图是定义一系列算法,将每个算法封装起来,并使它们可以...
享元模式是一种优化资源使用的软件设计模式,尤其适用于大量对象的场景。在C++编程中,享元模式通过共享技术来有效地支持大量细粒度的对象,以减少内存消耗。此模式的核心是运用共享技术来存储和管理具有相同状态的...
享元模式是软件设计模式中的一种结构型模式,它的主要目的是通过共享大量细粒度对象来减少内存的使用,提高系统性能。在许多场景下,尤其是处理大量相似对象时,享元模式能显著减少内存开销。这个压缩包文件...
- 享元模式(Flyweight):使用共享对象,有效地支持大量细粒度的对象。 3. **行为型模式**:这类模式关注对象之间的责任分配。 - 责任链模式(Chain of Responsibility):避免将请求的发送者和接收者耦合在一起...
享元模式是一种结构型设计模式,它通过共享已有对象来减少内存中对象的数量,从而达到提高系统性能的目的。在大型软件系统中,特别是在处理大量相似对象时,享元模式能够有效地减少内存开销,提高系统运行效率。在这...
享元模式则是一种结构型设计模式,它能通过共享技术有效地支持大量细粒度的对象。当系统中存在大量相似对象时,享元模式可以极大地减少内存的占用。享元模式通常与Flyweight接口、Concrete Flyweight(具体享元)、...
享元模式是软件设计模式中的一种结构型模式,它的主要目的是为了提高性能,尤其是在大量对象创建时。享元模式通过共享已有对象来减少内存中对象的数量,从而达到降低内存消耗的效果。这种模式适用于那些轻量级对象,...