`
greemranqq
  • 浏览: 974706 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论
阅读更多

一、介绍

       享元模式,英文(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常用设计模式-享元模式

    java常用设计模式-享元模式

    6.设计模式-享元模式1

    设计模式-享元模式 设计模式是软件设计中的一种解决方案,旨在提高代码的可维护性、灵活性和可重用性。享元模式(Flyweight Pattern)是结构型模式的一种,主要用于减少大量相似对象的内存占用,提高系统的性能和...

    设计模式-享元模式(讲解及其实现代码)

    享元模式是一种结构型设计模式,它通过共享已有对象来减少内存中对象的数量,从而达到降低系统内存占用、提高性能的目的。在软件工程中,当系统中存在大量相似或重复的对象时,享元模式尤为适用。 享元模式的核心是...

    JAVA-设计模式-结构型模式-享元模式

    JAVA-设计模式-结构型模式-享元模式

    设计模式--享元模式

    设计模式--享元模式

    c++设计模式-结构型模式-享元模式

    c++设计模式-结构型模式-享元模式;qt工程;c++简单源码; 享元(Flyweight)模式的定义:运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类...

    java基础设计模式模式 - 享元模式.7z

    享元模式是一种优化资源使用的软件设计模式,尤其适用于对象创建成本较高或系统内存有限的场景。在Java编程中,享元模式通过共享已有对象来减少内存中的对象数量,从而提高性能。这种模式的核心是实现细粒度对象的...

    XiaokangLei#CS-Notes-Plus#设计模式 - 享元1

    Flyweight:享元对象IntrinsicState:内部状态,享元对象共享内部状态ExtrinsicState:外部状态,每个享元对象的外部状态不同pub

    软件设计模式——享元模式设计报告

    享元模式是一种软件设计模式,它的主要目的是为了提高性能,减少对象的创建,尤其是在大量相似对象需要被创建的情况下。在给定的咖啡店案例中,享元模式的应用可以帮助优化内存使用,避免为每杯咖啡的配料表分配独立...

    设计模式-Java语言中的应用

    设计模式通常分为三类:创建型模式(如工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式),结构型模式(如适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式、享元模式)以及行为型模式(如...

    【Java设计模式-源码】享元模式

    Java中的享元设计模式对于优化内存使用和提高应用程序性能至关重要。通过最小化创建的对象数量,它显著减少了内存占用。享元模式的主要目标是在相似对象之间尽可能多地共享数据,从而提高效率和性能。 ## 二、详细...

    java设计模式---诙谐易懂版

    根据给定文件内容,以下是关于Java设计模式的知识点说明: 1. 策略模式(Strategy Pattern)是一种行为设计模式,允许在运行时选择算法的行为。策略模式的意图是定义一系列算法,将每个算法封装起来,并使它们可以...

    cpp代码-设计模式-享元模式

    享元模式是一种优化资源使用的软件设计模式,尤其适用于大量对象的场景。在C++编程中,享元模式通过共享技术来有效地支持大量细粒度的对象,以减少内存消耗。此模式的核心是运用共享技术来存储和管理具有相同状态的...

    设计模式的享元模式的例子

    享元模式是软件设计模式中的一种结构型模式,它的主要目的是通过共享大量细粒度对象来减少内存的使用,提高系统性能。在许多场景下,尤其是处理大量相似对象时,享元模式能显著减少内存开销。这个压缩包文件...

    设计模式精解-GoF-23种设计模式解析--附C++源代码

    - 享元模式(Flyweight):使用共享对象,有效地支持大量细粒度的对象。 3. **行为型模式**:这类模式关注对象之间的责任分配。 - 责任链模式(Chain of Responsibility):避免将请求的发送者和接收者耦合在一起...

    设计模式专题之(十二)享元模式---设计模式享元模式示例代码(python--c++)

    享元模式是一种结构型设计模式,它通过共享已有对象来减少内存中对象的数量,从而达到提高系统性能的目的。在大型软件系统中,特别是在处理大量相似对象时,享元模式能够有效地减少内存开销,提高系统运行效率。在这...

    设计模式----命令模式

    享元模式则是一种结构型设计模式,它能通过共享技术有效地支持大量细粒度的对象。当系统中存在大量相似对象时,享元模式可以极大地减少内存的占用。享元模式通常与Flyweight接口、Concrete Flyweight(具体享元)、...

    设计模式之享元模式

    享元模式是软件设计模式中的一种结构型模式,它的主要目的是为了提高性能,尤其是在大量对象创建时。享元模式通过共享已有对象来减少内存中对象的数量,从而达到降低内存消耗的效果。这种模式适用于那些轻量级对象,...

Global site tag (gtag.js) - Google Analytics