C#设计模式(13)——享元模式
1.享元模式介绍
在软件开发中我们经常遇到多次使用相似或者相同对象的情况,如果每次使用这个对象都去new一个新的实例会很浪费资源。这时候很多人会想到前边介绍过的一个设计模式:原型模式,原型模式通过拷贝现有对象来生成一个新的实例,使用拷贝来替代new。原型模式可以很好的解决创建多个相同/相似实例的问题,为什么还要用享元模式呢?这是因为这两种模式的使用场景是不同的,原型模式侧重于”创建“,我们通过拷贝确确实实的创建了新的实例,它属于创建型设计模式;而享元模式侧重于“重用”,即如果有现有的实例就不去创建了,直接拿来用就行了。
下面以大头儿子家开车为例介绍享元模式的用法。我们都知道大头儿子家里有三个人,这里就不用介绍了,家里现有一辆红色车和一辆蓝色车,小头爸爸,扁头妈妈和大头儿子开车时都是用家里现有的车,而不是每次开车都要新买一辆,只有想开的车家里没有时才会去买一辆,如大头儿子想开白色的车,但家里没有白色的车,这时候才去买一辆回来。我们直接在代码中理解享元模式的用法:
抽象车类Car定义了具体车共有的接口方法Use,无论什么车都就是可以用来开的,具体车类RealCar实现了Use接口。我们获取Car的实例不是通过new来获取,而是通过车库CarFactory的GetCar方法来获取,在GetCar方法中获取车时,首先判断车库中是否存在我们想要的车,如果有直接拿来用,如果没有才去买(new)一辆新车。
- ///抽象车类
- public abstract class Car
- {
- //开车
- public abstract void Use(Driver d);
- }
- /// <summary>
- /// 具体的车类
- /// </summary>
- public class RealCar : Car
- {
- //颜色
- public string Color { get; set; }
- public RealCar(string color)
- {
- this.Color = color;
- }
- //开车
- public override void Use(Driver d)
- {
- Console.WriteLine($"{d.Name}开{this.Color}的车");
- }
- }
- /// <summary>
- /// 车库
- /// </summary>
- public class CarFactory
- {
- private Dictionary<string, Car> carPool=new Dictionary<string, Car>();
- //初始的时候,只有红色和绿色两辆汽车
- public CarFactory()
- {
- carPool.Add("红色", new RealCar("红色"));
- carPool.Add("绿色", new RealCar("蓝色"));
- }
- //获取汽车
- public Car GetCar(string key)
- {
- //如果车库有就用车库里的车,车库没有就买一个(new一个)
- if (!carPool.ContainsKey(key))
- {
- carPool.Add(key, new RealCar(key));
- }
- return carPool[key];
- }
- }
- /// <summary>
- /// 司机类
- /// </summary>
- public class Driver
- {
- public string Name { get; set; }
- public Driver(string name)
- {
- this.Name = name;
- }
- }
客户端调用:
- class Program
- {
- static void Main(string[] args)
- {
- CarFactory carFactory = new CarFactory();
- //小头爸爸开蓝色的车
- Driver d1 = new Driver("小头爸爸");
- Car c1=carFactory.GetCar("蓝色");
- c1.Use(d1);
- //扁头妈妈开蓝色的车
- Driver d2 = new Driver("扁头妈妈");
- Car c2 = carFactory.GetCar("蓝色");
- c2.Use(d2);
- if (c1.Equals(c2))
- {
- Console.WriteLine("小头爸爸和扁头妈妈开的是同一辆车");
- }
- //车库没有白色的车,就new一辆白色的车
- Driver d3 = new Driver("大头儿子");
- Car c3 = carFactory.GetCar("白色");
- c3.Use(d3);
- Console.ReadKey();
- }
- }
运行程序结果如下:我们可以看到小头爸爸和扁头妈妈用的是同一辆车,就是复用了一个实例。
在使用享元模式时一个最大的问题是分离出对象的外部状态和内部状态。我们把对象内部的不会受环境改变而改变的部分作为内部状态,如例子中车的颜色,车的颜色不会随着外部因素司机的不同而改变;外部状态指的是随环境改变而改变的部分,对车来说,司机就是外部状态,我们可以通过公共接口的参数来传入外部状态。
2.小结
上边例子的类图
享元模式的使用场景:
当系统中大量使用某些相同或者相似的对象,这些对象要耗费大量的内存,并且这些对象剔除外部状态后可以通过一个对象来替代,这时可以考虑使用享元模式。在软件系统中享元模式大量用于各种池技术,如数据库连接对象池,字符串缓存池,HttpApplication池等。
享元模式的优点:
通过对象的复用减少了对象的数量,节省内存。
享元模式的缺点:
需要分离对象的外部状态和内部状态,使用不当会引起线程安全问题,提高了系统的复杂度。
C#设计模式(13)——享元模式的更多相关文章
- python设计模式之享元模式
python设计模式之享元模式 由于对象创建的开销,面向对象的系统可能会面临性能问题.性能问题通常在资源受限的嵌入式系统中出现,比如智能手机和平板电脑.大型复杂系统中也可能会出现同样的问题,因为要在其 ...
- 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)
原文:乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) 作者:weba ...
- 设计模式之享元模式(Flyweight)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于怎样创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...
- 【php设计模式】享元模式
享元模式其实就是共享独享模式,减少重复实例化对象的操作,从而将实例化对象造成的内存开销降到最低. 享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象.我们将通过创建 5 个对象来画出 ...
- PHP设计模式之享元模式
享元模式,"享元"这两个字在中文里其实并没有什么特殊的意思,所以我们要把它拆分来看."享"就是共享,"元"就是元素,这样一来似乎就很容易理解 ...
- 【GOF23设计模式】享元模式
来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_享元模式.享元池.内部状态.外部状态.线程池.连接池 package com.test.flyweight; /** * ...
- Head First设计模式之享元模式(蝇量模式)
一.定义 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式. ...
- 【Unity3D与23种设计模式】享元模式(Flyweight)
GoF中定义: "使用共享的方式,让一大群小规模对象能更有效地运行" 享元模式一般应用在游戏角色属性设置上 游戏策划需要通过"公式计算"或者"实际测试 ...
- Java进阶篇设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
- Java设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
随机推荐
- Codeforces551 C. GukiZ hates Boxes
二分答案 + 贪心 传送门:$>here<$ $Solution$ 二分时间+贪心验证.思维难度主要在验证上,然而坑人的点却在n的取值上.那么先来谈如何验证.在已知时间的条件下,能否用一种 ...
- 自学Linux命令行与Shell脚本之路
自学Linux命令行与Shell脚本之路[第一回]:初识Linux 1.1 自学Linux Shell1.1-Linux初识 1.2 自学Linux Shell1.2-Linux目录结构 1.3 ...
- 【arc073f】Many Moves(动态规划,线段树)
[arc073f]Many Moves(动态规划,线段树) 题面 atcoder 洛谷 题解 设\(f[i][j]\)表示第一个棋子在\(i\),第二个棋子在\(j\)的最小移动代价. 发现在一次移动 ...
- [2017-8-02]Android Learning Day9
Layout动画效果 为布局添加简单的动画效果 public class MainActivity extends AppCompatActivity { @Override protected vo ...
- Docker普通用户不使用sudo提权
解决方法 sudo groupadd docker 添加Docker用户组 sudo gpasswd -a ${USER} docker 添加你的用户到Docker用户组 reboot 重启系统.也可 ...
- A1006. Sign In and Sign Out
At the beginning of every day, the first person who signs in the computer room will unlock the door, ...
- Django(十三)ajax 与 Bootstrap,font-awesome
prop,attr,val font-awesome:字体,图标库 对话框添加,删除,修改: 添加: Ajax偷偷向后台发请求: 1. 下载引入jQuery 2. $.ajax({ url: '/ad ...
- __int128
__int128 __uint128 __int128_t __uint128_t 大小:16字节 2^128(sizeof()) 2^128 39位 340282366920938463463374 ...
- OmniPlan,一款让你无法自拔的项目管理工具(仅适用于MAC系统)
OmniPlan 大家都知道Windows系统可以使用project来方便的管理跟踪项目的各项任务,那么Mac系统有没有这样专业级的项目管理软件了?答案是有,今天给大家推荐的Mac系统下的项目管理 ...
- bash 6
1)如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢? 每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数, 没有地方调用这个函数,这块 ...