享元模式浅析

源码面前,了无秘密。

1 package com.xiaolu.flyweightdemotest;
 2
 3
 4 import org.junit.Assert;
 5 import org.junit.Test;
 6
 7 import com.xiaolu.flyweight.FlyweigthtFactory;
 8 import com.xiaolu.flyweight.IChess;
 9
10
11
12 /***
13  * 享元模式:flyweight有轻量的意思。享元即共享。这里的轻量到底指什么?
14  *
15  * 在享元模式中分为内蕴状态和外蕴状态
16  * 其中:
17  * 1) 内蕴状态是不随环境而改变的,因此可以用用于共享。 (而一个对象中的内蕴状态很少,flyweight更多的表明了这个模式的用途---轻量级对象的共享)
18  * 2) 外蕴状态是随着环境的变化而变化的。外蕴状态一般是由外部传入的。
19  *
20  * 享元模式定义: 所谓享元模式就是运行共享技术有效地支持大量细粒度对象的复用。   ps: 细粒度(其实也就是因为内蕴状态少,因此对象"小"----可以从内存的观点去考虑)
21  * 使用享元模式的场景是: 当系统需要大量创建对象时,如果能够使用享元模式可以大量节省内存,提高效率。
22  *
23  * 在这里思考一个问题:为什么是细粒度的? 也就是为什么是"小"对象(内蕴状态很少的)对象进行共享呢? 如果多了会如何,内蕴状态多了进行共享不是更能节省内存,享元模式的意义更大吗?
24  *     所谓能够共享,即多个对象内部的状态应当是一样的,否则就谈不上共享。那么如果一个对象的内蕴状态越多,能共享的可能性就越低。【如果有一个对象只有一个属性和有10个属性的对象,哪个更
25  * 容易共享呢? 如果A、B、C三个客户想要共享,那么如果有10个内蕴状态的,就需要10个属性都一致,A、B、C三个客户才可以共享。而 一个属性的则就方便多了。 当然多个属性的也并非不能共享,
26  * 但是从现实场景考虑-----还是算了】
27  *
28  * 但是还有一个问题: 是不是属性越少的就可以去使用享元模式进行共享?
29  *     不见得。那怕只有一个属性,但是如果属性的取值范围很大(甚至是任意的),那么享元模式基本上就没什么意义(每次都是创建新的)
30  *
31  * java中的String类型即使用了享元模式 "abc" == "abc" , 两个相同字符串共享同一个String对象。 ps:但是因为字符串相等,包括长度和顺序,因此如果一个程序中
32  * 没有任何两个字符串是相等的(equals),那么显然也就不能"共享"了。当然从大的范围看,还是有很多情况下,相同字符串多次出现的(否则sun也不傻......)
33  *
34  *
35  * 我觉得经典使用享元模式的场景是: 五子棋 (围棋) , 英文字符的书写。
36  * 五子棋,不管有多少个,都是只有黑白两色。只是分布在不同的位置。因此就可以使用享元模式(白色棋子、黑色棋子共享),而放置的位置信息则可以通过外蕴状态来输入。
37  * 英文字符。26*2 = 52个(大小写),其他的位置、颜色、粗细等,可以通过外部来传入。(否则一篇文章有多长,需要创建多少个对象?一本书呢?哦.....)
38  *
39  *
40  * 还有复合享元,下次有时间再看。
41  *
42  * @author xiaolu 2018年10月11日
43  */
44 public class TestFlyweight {
45     @Test
46     public void test_StringFlyweight() throws Exception {
47         String a = "xiaolu";
48         String b = "xiaolu";
49         Assert.assertTrue(a == b);
50     }
51
52
53     @Test
54     public void test_flyweightdemo() throws Exception {
55         IChess black = FlyweigthtFactory.INSTANCE.get("black");// 黑色棋子
56         IChess white = FlyweigthtFactory.INSTANCE.get("white");//白色棋子
57         // 外蕴状态即是位置,通过外部参数传入
58         black.put(10, 10);
59         white.put(100, 100);
60         black.put(12, 12);
61         white.put(30, 30);
62         black.put(15 , 15 );
63         white.put(100, 100);
64
65         // 因为有工厂的存在不用过多思考,一共创建了2个对象。【就是把black换成FlyweigthtFactory.INSTANCE.get("black")】也没什么区别,除了写起来麻烦。
66     }
67
68
69 }
 1 package com.xiaolu.flyweight;
 2
 3 /**
 4  * 享元接口  此接口往往定义了享元对象的提供的行为,将外蕴状态通过行为的参数来传入
 5  * @author xiaolu 2018年10月11日
 6  */
 7 public interface IChess {
 8
 9     /***
10      * 假设的放置棋子的方法 x, y 分别代表坐标
11      * @param x
12      * @param y
13      */
14     public void put(int x , int y);
15 }
 1 package com.xiaolu.flyweight;
 2
 3 public class Chess implements IChess {
 4     private String color;
 5
 6     /**
 7      * 网上资料将此处传入的常常称为"外蕴状态",个人觉得更应该叫做“内蕴状态”或者 "内蕴状态的对应者"
 8      * 没有这种对应,无法知道你想要"共享什么内蕴"的对象。
 9      *
10      * @author : xiaolu 2018年10月11日
11      */
12     public Chess(String color) {
13         this.color = color;
14     }
15
16     @Override
17     public void put(int x, int y) {
18         System.out.println(this.color + " 棋 放在 x=" + x + ", y=" + y + "的位置.");
19     }
20
21 }
 1 package com.xiaolu.flyweight;
 2
 3 import java.util.HashMap;
 4 import java.util.Map;
 5
 6 /**
 7  * 享元工厂,采用单例实现(此处通过enum来实现,线程安全,规避反序列化-----新学到东西的一次实践)
 8  * ps:莫名就想起了cache----------------
 9  * @author xiaolu 2018年10月11日
10  */
11 public enum FlyweigthtFactory {
12     INSTANCE;
13
14     private Map<String, IChess> chesses = new HashMap<String, IChess>(2);
15
16     private FlyweigthtFactory() {
17         chesses.put("black", new Chess("black"));
18         chesses.put("white", new Chess("white"));
19     }
20
21     /**
22      * 此处有一个有趣的地方:应该使用assert 呢还是,if判断抛异常?
23      * 使用assert ,assert在调试时,打开jre -ea即可起作用,而在产品中则一般不会开启-ea,从而省去了代码检查。关键点在于:
24      *     用户的输入点是需要我们去进行判断的(因为不知道从界面上获取的用户输入会如何-----思维跳出当前这个五子棋吧 ,  ,想想java-web开发,应该在controller就进行输入验证)。而此处逻辑是我们程序
25      * 自己内部调用的,如果此处去检查抛出异常,那么就是前面没有进行错误检查处理。属于程序逻辑设计问题了。
26      * 在开发时内部使用assert,一旦测试通过,则可以忽略掉。毕竟层层检查有时候是无意义并且浪费效率的。(此处也是借鉴了《大道至简》上的思维)
27      * @param color
28      * @return
29      */
30     public IChess get(String color) {
31         assert chesses.containsKey(color);
32
33         /*
34          * 一般是如此实现----(cache的方式),由于五子棋,我们知道就是黑白两色,因此在构造函数中直接构造,也就不需要此处再去判断加入了。若范围不确定,则需要(就是一般cache的实现思维)
35          *
36          * if(!chesses.containsKey(color)){
37          *    chesses.put(color,new Chess(color));
38          *  }
39         */
40         return chesses.get(color);
41     }
42 }

原文地址:https://www.cnblogs.com/xiao-lu/p/9775820.html

时间: 2024-10-18 02:26:47

享元模式浅析的相关文章

享元模式(结构型)

思考问题:设计一个围棋游戏,模拟一个下棋动作,如何设计? 解答:很直接的,我们会设计一个棋盘类Chessboard,一个棋子类Chesspiece,每下一枚棋子时就new一个棋子对象(传入颜色.位置),然后将这些棋子装入到一个容器中. 这种简单粗暴的方式确实是解决了问题,但你会发现,棋子永远只有黑白色,棋子对象的函数都是一样的, 主要的变化只是(x,y)位置而已,那能不能单独把(x,y)独立出来让调用者管理(而非记录到棋子内部),让棋子对象变成一个可重用的对象呢?这样就可以避免产生大量棋子对象了

[工作中的设计模式]享元模式模式FlyWeight

一.模式解析 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持大量的细粒度对象. 享元模式:主要为了在创建对象时,对共有对象以缓存的方式进行保存,对外部对象进行单独创建 模式要点: 1.享元模式中的对象分为两部分:共性部分和个性化部分,共性部分就是每个对象都一致的或者多个对象可以共享的部分,个性化部分指差异比较大,每个类均不同的部分 2.共性部分的抽象就是此模

享元模式

1,我们做产品的时候,有很多产品是大同小异,所以我们细分化模块化是为了共用,而享元模式就是 2,代码很简单,看注视很清楚 // 享元模式.cpp : 定义控制台应用程序的入口点. // //公共的地方,仅仅需要一个对象在程序中, //放在了map 中,由于map特性一个key 只能有一个value瞒住享元模式要求 //最大用处,内存优化,目的是降低程序内存使用 #include "stdafx.h" #include <iostream> #include <stri

设计模式之结构型模式—— 2.6 享元模式

<?php /**  * 2.6 享元模式  *   定义:  *       运用共享技术有效地支持大量细粒度的对象.  *   角色:  *       1. 抽象享元(Flyweight)类  *           职责:所有具体享元类的超类或接口,  *                 通过这个接口,享元类可以接  *                 受并作用于外部状态.  *       2. 具体享元类  *           职责:继承享元抽象类,并为内部状态  *      

设计模式-享元模式

***********************************************声明****************************************************** 原创作品,出自 "晓风残月xj" 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj). 由于各种原因,可能存在诸多不足,欢迎斧正! *******************************************

Java设计模式菜鸟系列(二十一)享元模式建模与实现

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/40021651 享元模式(Flyweight):运用共享的技术有效地支持大量细粒度的对象.主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销.在某种程度上,你可以把单例看成是享元的一种特例. 一.uml建模: 二.代码实现 /** * 享元模式(Flyweight):运用共享的技术有效地支持大量细粒度的对象. * * 主要目的是实现对象的共享,即共享池,当系统中对象

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

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

iOS设计模式——享元模式

公共交通(如公共汽车)已有一百多年的历史了.大量去往相同方向的乘客可以分担保有和经营车辆(如公共汽车)的费用.公共汽车有多个站台,乘客沿着路线在接近他们目的地的地方上下车.到达目的地的费用仅与行程有关.跟保有车辆相比,乘坐公共汽车要便宜得多.这就是利用公共资源的好处. 在面向对象软件设计中,我们利用公共对象不仅能节省资源还能提高性能.比方说,某个人物需要一个类的一百万个实例,但我们可以把这个类的一个实例让大家共享,而把某些独特的信息放在外部,节省的资源可能相当可观(一个实例与一百万个实例的差别)

《JAVA与模式》之享元模式

Flyweight在拳击比赛中指最轻量级,即"蝇量级"或"雨量级",这里选择使用"享元模式"的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持大量的细粒度对象. Java中的String类型 在JAVA语言中,String类型就是使用了享元模式.String对象是final类型,对象一旦创建就不可改变.在JAVA中字符串常量都是存在常量池中的,JAVA会确保一个字符串常量在常量池中只有一个拷贝.Stri