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设计模式之七 ----- 享元模式和代理模式
前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...
随机推荐
- POI如何自动调整Excel单元格中字体的大小
问题 目的是要将Excel中的文字全部显示出来,可以设置对齐格式为[缩小字体填充],但是这样的话只能展示出一行数据,字体会变得很小.还有一种办法,设置对齐格式为[自动换行],然后让单元格中的字体自动调 ...
- 【HDU3032】Nim or not Nim?(博弈论)
[HDU3032]Nim or not Nim?(博弈论) 题面 HDU 题解 \(Multi-SG\)模板题 #include<iostream> #include<cstdio& ...
- emwin之基于某个事件或标志创建某个界面的一种方法
@2018-12-11 [小记] 例:定时器事件到来后切换至某个界面, 即在原始界面上发生跳转,在新界面上可返回至原始界面,可使用如下方法: a,在定时器事件发生后给原始界面中的自定义消息发送一条该自 ...
- notepad++设置(不断更新)
1.主题设置 主题名称:Obsidian 字体字号:Courier New 10 设置方法: 设置---语言格式设置---选择主题,同时勾选“使用全局字体”“使用全局字体大小 补充一点: 修改两处地方 ...
- HR_Sherlock and Anagrams_TIMEOUT[UNDONE]
2019年1月10日15:39:23 去掉了所有不必要的循环区间 还是超时 本地运行大概3s #!/bin/python3 import math import os import random im ...
- 前端基础-- CSS
CSS知识 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素. 当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染).Css之车更丰富的文档外 ...
- Zabbix监控服务器硬盘状态
安装Iptables服务: [root@localhost /]# yum install iptables-services [root@localhost /]# vim /etc/sysconf ...
- Nginx实践篇(2)- Nginx作为静态资源web服务 - 控制浏览器缓存、防盗链
一.控制浏览器缓存 1. 浏览器缓存简介 浏览器缓存遵循HTTP协议定义的缓存机制(如:Expires;Cache-control等). 当浏览器无缓存时,请求响应流程 当浏览器有缓存时,请求响应流程 ...
- js小结
1,浏览器对json支持的方法: JSON.parse(jsonstr);将string转为json的对象. JSON.stringify(jsonobj);将json对象转为string. 2,js ...
- node.js中的文件系统
文件打开操作 fs.open(path, flags[, mode], callback) path: <string>|<Buffer>|<URL> flags: ...