c#享元模式详解
基本介绍:
享元模式的定义:运用共享技术有效地支持大量细粒度的对象重复使用。适用于大量小粒度的对象造成的运行效率和内存使用效率低下的情况。
“享元”顾名思义,“享”共享的意思,“元”单元,最小对象,零部件的意思。
即从字面意思不难看出,该模式旨在共享一些零部件供其使用。
想要实现对这些零部件的重复使用,那必然需要一个类来统筹安排,负责它们的创建、使用和维护。
如果想要实现一个零部件的使用,可以使用单例模式,所以享元模式其实也可以看做是单例模式的复数模式。
它们都是在一个固定类中对对象进行创建和维护。
举例说明:
比如五子棋游戏,构成游戏的组件,无非就是无数个黑棋和白棋。
黑棋和白棋就可以看做是两个最小的单元,在对战过程中就是在重复的创建这些单元。
如果是一般模式一盘棋局必然要创建N多个黑棋和白棋的对象,如果是一盘游戏还可以凑合使用。
大家想象一下,如果是个游戏平台,可以同时开展1000盘这样的棋局,那必然需要创建N*1000个黑白棋子对象。
其实这些对象都是重复的,只有很少一部分属性(状态)不同而已,相同的是棋子本身,不同的是棋子的颜色,比如黑棋和白棋之分。
另外该棋子在哪个棋盘、在哪个棋盘坐标就属于不可被共享的部分了,这部分内容就是非共享的。
既然弄清楚了相同的部分和不同部分,我们就可以把相同的部分进行共享,对象个数从原来的N*1000个对象降到了2个对象。
基本结构:
通过例子也不难看出,享元模式创建的对象存在两个状态:
内部状态:可以被共享的状态。存储在享元信息内部,并且不会随环境的改变而改变。在这里指的是棋子本身,它们不会随着棋局和选手的变化而变化。
外部状态:不可被共享的状态。随环境的改变而改变。在这里指的是黑白棋子颜色之分。
这里容易让人产生误区,容易把棋子所处坐标和棋盘等归在外部状态,这就大错特错了。
能共享的都是最基本的单元,而棋子的坐标和棋盘是不断变化的,随着棋局的不同而不同,这部分是不可以被共享的,也不能被共享。
享元模式的主要有以下角色:
抽象享元角色(Flyweight):通常是一个接口或抽象类,声明了具体享元类公共的方法,这些方法可以为外界提供内部状态和设置外部状态。
具体享元角色(Concrete Flyweight):实现了抽象享元类,在该类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。
非享元角色 (Unsharable Flyweight):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。本实例中,棋盘类就是非享元部分。
享元工厂角色(Flyweight Factory):负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
优缺点:
优点:降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。享元模式中的外部状态相对独立,且不影响内部状态。
缺点:为了使对象可以共享,需要将享元对象的部分状态外部化,分离内部状态和外部状态,这使得程序的逻辑更复杂,使系统复杂化。
具体实例:
抽象享元角色
1 /// <summary>
2 /// 享元抽象类
3 /// </summary>
4 public abstract class ChessPieces
5 {
6 public string Colour;
7 public ChessPieces(string strColour)
8 {
9 Colour = strColour;
10 }
11
12
13 /// <summary>
14 /// 落子规则
15 /// </summary>
16 /// <param name="chessBoard">棋盘信息</param>
17 public void MoveInChess(ChessBoard chessBoard)
18 {
19 //这里可以将棋盘信息通过参数方式注入
20 }
21
22 //还可以设置一些 棋子的规则等等
23 }享元抽象类主要是规范具体享元类供其继承,并提供其共有的属性和方法。
本实例只是最简单的使用构造函数参数注入方式,将棋子外部状态(颜色)更新。
而内部状态,比如棋子的具体下棋规则等等,可以在此类中声明。
比如此实例MoveInChess方法就是通过参数注入的形式将棋盘信息注入到内容,从而落实落子的具体规则。
规则是通用的,可以共享的,所以可以是内部状态的一部分。
- 具体享元角色
1 /// <summary>
2 /// 白棋
3 /// </summary>
4 public class BlackPieces : ChessPieces
5 {
6 public BlackPieces(string strColour) : base(strColour)
7 {
8
9 }
10 }
11
12 /// <summary>
13 /// 黑棋
14 /// </summary>
15 public class WhitePieces : ChessPieces
16 {
17 public WhitePieces(string strColour) : base(strColour)
18 {
19
20 }
21 }继承自抽象享元类,具体实现其方法。
此实例只是通过构造函数简单的将棋子分成黑白棋子,实际中会有各种属性或方法需要在此类中实现。
- 享元工厂角色
/// <summary>
/// 棋子工厂
/// </summary>
public class WuziqiFactory
{
// 单例模式工厂
private static WuziqiFactory wuziqiFactory;
// 缓存存放共享对象
private static Dictionary<string, ChessPieces> keyValuePairs = new Dictionary<string, ChessPieces>();
// 私有化构造方法
private WuziqiFactory()
{
if (keyValuePairs.Count == 0)
{
keyValuePairs.Add("Black", new BlackPieces("Black"));
keyValuePairs.Add("White", new WhitePieces("White"));
}
} // 获得单例工厂
public static WuziqiFactory GetInstance
{
get
{
if (wuziqiFactory == null)
{
wuziqiFactory = new WuziqiFactory();
}
return wuziqiFactory;
}
} // 获取棋子
public ChessPieces GetChessPieces(String type)
{
if (keyValuePairs.ContainsKey(type))
{
return keyValuePairs[type];
}
return null;
}
}此实例使用单例模式创建工厂对象,保证整个项目生命周期内只存在一个棋子工厂对象,并使用GetInstance进行返回具体对象。这里可以加上锁防止并发等问题。
另外工厂的构造函数对可共享对象进行了缓存,使用GetChessPieces获取棋子对象时,可保证其不重复创建。保证整个项目生命周期内只存在黑白两个棋子对象。
- 非享元角色
1 /// <summary>
2 /// 棋盘
3 /// </summary>
4 public class ChessBoard
5 {
6 //棋盘编号
7 public int ChessBoardId { get; set; }
8
9
10 //黑方棋手
11 //白方棋手
12 //棋盘棋子布局等等属性
13
14 /// <summary>
15 /// 初始化棋盘
16 /// </summary>
17 public ChessBoard()
18 {
19 //可以通过构造函数 初始化棋盘基础属性
20 }
21 }非享元部分,也就是不能共享的部分。
棋盘的编号、棋盘对局双方信息和棋盘落子情况等都是每个棋盘独有的,不可共享。
至于棋盘的落子和整体维护可以通过参数注入等形式交给棋子共享对象进行研判和操作,或者直接在棋盘类中进行声明都可以,这就看具体制定的规则了。
客户端
1 /// <summary>
2 /// 客户端
3 /// </summary>
4 class Client
5 {
6 static void Main(string[] args)
7 {
8 //创建棋盘 通过构造函数或者函数参数等形式初始化棋手、棋盘信息
9 ChessBoard chessBoard = new ChessBoard();
10 //获取黑方棋子1
11 ChessPieces blackPieces1 = WuziqiFactory.GetInstance.GetChessPieces("Black");
12 Console.WriteLine("棋子:" + blackPieces1.Colour);
13 //获取白方棋子1
14 ChessPieces whitePieces1 = WuziqiFactory.GetInstance.GetChessPieces("White");
15 Console.WriteLine("棋子:" + whitePieces1.Colour);
16
17 //判断两个棋子是否是同一个对象
18 Console.WriteLine("判断两个不同颜色的棋子是否是同一个对象" + blackPieces1.Equals(whitePieces1) + "\r\n");
19
20 //获取黑方棋子2
21 ChessPieces blackPieces2 = WuziqiFactory.GetInstance.GetChessPieces("Black");
22 Console.WriteLine("棋子:" + blackPieces2.Colour);
23 //获取白方棋子2
24 ChessPieces whitePieces2 = WuziqiFactory.GetInstance.GetChessPieces("White");
25 Console.WriteLine("棋子:" + whitePieces2.Colour);
26
27 //判断同一个颜色的两个棋子是否是同一个对象
28 Console.WriteLine("判断两个不同颜色的棋子是否是同一个对象" + blackPieces1.Equals(blackPieces2) + "\r\n");
29
30 Console.ReadKey();
31 }
32 }
总结:
实现享元工厂类时使用单例模式和简单工厂模式,确保对象的唯一性,并提供方法向客户端返回享元对象。
c#享元模式详解的更多相关文章
- 【享元设计模式详解】C/Java/JS/Go/Python/TS不同语言实现
简介 享元模式(Flyweight Pattern),是一种结构型设计模式.主要用于减少创建对象的数量,以减少内存占用和提高性能.它摒弃了在每个对象中保存所有数据的方式,通过共享多个对象所共有的相同状 ...
- C#设计模式:享元模式(Flyweight Pattern)
一,什么是享元模式? 享元模式(Flyweight Pattern):采用共享技术来避免大量拥有相同内容对象的开销,主要用于减少创建对象的数量,以减少内存占用和提高性能 1,根本的思路就是对象的重用2 ...
- java开发中的23中设计模式详解--大话设计模式
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- java23中设计模式详解
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- 设计模式之享元模式(Flyweight)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于怎样创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...
- JAVA 23种开发模式详解(代码举例)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- Java开源生鲜电商平台-盈利模式详解(源码可下载)
Java开源生鲜电商平台-盈利模式详解(源码可下载) 该平台提供一个联合买家与卖家的一个平台.(类似淘宝购物,这里指的是食材的购买.) 平台有以下的盈利模式:(类似的平台有美菜网,食材网等) 1. 订 ...
- 重学 Java 设计模式:实战享元模式「基于Redis秒杀,提供活动与库存信息查询场景」
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 程序员的上下文是什么? 很多时候一大部分编程开发的人员都只是关注于功能的实现,只 ...
- Flyweight(享元模式)
import java.util.Hashtable; /** * 享元模式 * @author TMAC-J * 享元模式一般和工厂模式一起使用,但此处为了更好说明,只用享元模式 * 定义:享元模式 ...
- 设计模式(十二)享元模式(Flyweight Pattern)
一.引言 在软件开发过程,如果我们需要重复使用某个对象的时候,如果我们重复地使用new创建这个对象的话,这样我们在内存就需要多次地去申请内存空间了,这样可能会出现内存使用越来越多的情况,这样的问题是非 ...
随机推荐
- [Spring+SpringMVC+Mybatis]框架学习笔记(五):SpringAOP_顾问
上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP 下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(六):Spring_A ...
- Linux 问题:网络相关
防火墙 同网段双网卡 双网关 看服务日志
- 论文解读(BERT-DAAT)《Adversarial and Domain-Aware BERT for Cross-Domain Sentiment Analysis》
论文信息 论文标题:Adversarial and Domain-Aware BERT for Cross-Domain Sentiment Analysis论文作者:论文来源:2020 ACL论文地 ...
- redis 中的 字符串
String是redis 中的最基本的类型, 为二进制安全 ,意味着String可以表示各种类型 一个字符串value 最大为 521M set k1 v100 set k2 v200 get 命 ...
- flash 游戏分析 - 1
游戏 我们就以<猎人的生存日记>(Orion Sandbox)这款游戏来分析. 下载链接 用FlashStart打开Orion Sandbox 1.swf 我们需要反复进入游戏,可以先打开 ...
- BugKu:文件包含+php伪协议
这道题一进去发现一个超连接点击后发现跳转到了如下页面url如下/index.php?file=show.php,觉得这道题应该是一个php伪协议的应用 1 php://filter php://fil ...
- 好用工具:Wappalyzer
说明 这个插件可以检测到网站使用的技术栈,是一个好玩的技术嗅探插件 安装 使用
- WPF自定义控件之消息提示
创建消息提示控件 internal class Message : ContentControl { public int Time { get; set; } [Bindable(true)] pu ...
- 一 APPIUM基本理论知识(转)
1.APPIUM介绍 Appium 是一个自动化测试开源工具,支持 iOS 平台和 Android 平台上的原生应用,web 应用和混合应用.所谓的"移动原生应用"是指那些用 iO ...
- [elasticsearch]部署安装单节点和集群
单点安装 进入安装目录:cd /usr/local 获取安装包: wget http://172.29.50.31/download/ProgramPackage/elasticsearch/elas ...