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设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
随机推荐
- Codeforces Round #545 (Div. 2) D
链接:http://codeforces.com/contest/1138/problem/D 啊啊啊啊啊啊,自闭啊,比赛的时候判断条件 if(s1[i-1]=='0') aa++;写成了 if(s1 ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- 【宝塔linux】 导入mysql 大文件失败的问题
导入数据库有四种方法 1.宝塔网站自带的数据库导入 2.phpmyadmin导入 3.远程到linux服务器用导入命令 使用xshell进入到控制台 1.首先建空数据库 mysql>create ...
- 爬虫_糗事百科(scrapy)
糗事百科scrapy爬虫笔记 1.response是一个'scrapy.http.response.html.HtmlResponse'对象,可以执行xpath,css语法来提取数据 2.提取出来的数 ...
- windows 服务器同步互联网时间
@echo off ::netsh ipsec static set policy name=7road assign=n net time /setsntp:pool.ntp.org net sto ...
- Centos 6.x/7.x yum安装php5.6.X
鉴于Centos 默认yum源的php版本太低了,手动编译安装又有点一些麻烦,那么如何采用Yum安装的方案安装最新版呢.那么,今天我们就来学习下如何用yum安装php最新版. 1.检查当前安装的PHP ...
- Linux的wget命令详解【转载】
Linux wget是一个下载文件的工具,它用在命令行下.对于Linux用户是必不可少的工具,尤其对于网络管理员,经常要下载一些软件或从远程服务器恢复备份到本地服务器.如果我们使用虚拟主机,处理这样的 ...
- Java中数组判断元素存在几种方式比较详解
1. 通过将数组转换成List,然后使用List中的contains进行判断其是否存在 public static boolean useList(String[] arr,String contai ...
- javascript之判断专题
javascript有数组,对象,函数,字符串,布尔,还有Symbol,set,map,weakset,weakmap. 判断这些东西也是有很多坑,像原生的typeof,instanceOf有一些bu ...
- js jquery数组去重
数组去重建议直接使用jquery的 $.unique(arr);方法,此外比较好的方法是本文中的unique3方法比较快用了一个hash表,就是所谓的空间换时间.本文还提供了很多其他写法,都是大同小异 ...