当前位置: 首页 >  网技达人 >  c#享元模式详解

c#享元模式详解

导读:基本介绍:.享元模式的定义:运用共享技术有效地支持大量细粒度的对象重复使用。适用于大量小粒度的对象造成的运行效率和内存使用效率低下的情况。.“享元”顾名思义,“享”共享的意思,“元”单元,最小对象,零部件的意思。.即从字面意思不难看出,该模式旨在共享一些零部件供其使用。.想要实现

基本介绍:

享元模式的定义:运用共享技术有效地支持大量细粒度的对象重复使用。适用于大量小粒度的对象造成的运行效率和内存使用效率低下的情况。

“享元”顾名思义,“享”共享的意思,“元”单元,最小对象,零部件的意思。

即从字面意思不难看出,该模式旨在共享一些零部件供其使用。

想要实现对这些零部件的重复使用,那必然需要一个类来统筹安排,负责它们的创建、使用和维护。

如果想要实现一个零部件的使用,可以使用单例模式,所以享元模式其实也可以看做是单例模式的复数模式。

它们都是在一个固定类中对对象进行创建和维护。

举例说明:

比如五子棋游戏,构成游戏的组件,无非就是无数个黑棋和白棋。

黑棋和白棋就可以看做是两个最小的单元,在对战过程中就是在重复的创建这些单元。

如果是一般模式一盘棋局必然要创建N多个黑棋和白棋的对象,如果是一盘游戏还可以凑合使用。

大家想象一下,如果是个游戏平台,可以同时开展1000盘这样的棋局,那必然需要创建N*1000个黑白棋子对象。

其实这些对象都是重复的,只有很少一部分属性(状态)不同而已,相同的是棋子本身,不同的是棋子的颜色,比如黑棋和白棋之分。

另外该棋子在哪个棋盘、在哪个棋盘坐标就属于不可被共享的部分了,这部分内容就是非共享的。

既然弄清楚了相同的部分和不同部分,我们就可以把相同的部分进行共享,对象个数从原来的N*1000个对象降到了2个对象。

基本结构:

通过例子也不难看出,享元模式创建的对象存在两个状态:

内部状态 :可以被共享的状态。存储在享元信息内部,并且不会随环境的改变而改变。在这里指的是棋子本身,它们不会随着棋局和选手的变化而变化。

外部状态 :不可被共享的状态。随环境的改变而改变。在这里指的是黑白棋子颜色之分。

这里容易让人产生误区,容易把棋子所处坐标和棋盘等归在外部状态,这就大错特错了。

能共享的都是最基本的单元,而棋子的坐标和棋盘是不断变化的,随着棋局的不同而不同,这部分是不可以被共享的,也不能被共享。

享元模式的主要有以下角色:

抽象享元角色(Flyweight):通常是一个接口或抽象类,声明了具体享元类公共的方法,这些方法可以为外界提供内部状态和设置外部状态。

具体享元角色(Concrete Flyweight):实现了抽象享元类,在该类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。

非享元角色 (Unsharable Flyweight):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。本实例中,棋盘类就是非享元部分。

享元工厂角色(Flyweight Factory):负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

优缺点:

优点:降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。享元模式中的外部状态相对独立,且不影响内部状态。

缺点:为了使对象可以共享,需要将享元对象的部分状态外部化,分离内部状态和外部状态,这使得程序的逻辑更复杂,使系统复杂化。

具体实例:

  1. 抽象享元角色

     1     /// <summary>
    

    2 /// 享元抽象类 3 /// 4 public abstract class ChessPieces 5 { 6 public string Colour; 7 public ChessPieces(string strColour) 8 { 9 Colour = strColour; 10 } 11 12
    13 ///

    14 /// 落子规则 15 /// 16 /// 棋盘信息 17 public void MoveInChess(ChessBoard chessBoard) 18 { 19 //这里可以将棋盘信息通过参数方式注入 20 } 21 22 //还可以设置一些 棋子的规则等等 23 }

享元抽象类主要是规范具体享元类供其继承,并提供其共有的属性和方法。

本实例只是最简单的使用构造函数参数注入方式,将棋子外部状态(颜色)更新。

而内部状态,比如棋子的具体下棋规则等等,可以在此类中声明。

比如此实例MoveInChess方法就是通过参数注入的形式将棋盘信息注入到内容,从而落实落子的具体规则。

规则是通用的,可以共享的,所以可以是内部状态的一部分。

  1. 具体享元角色

     1     /// <summary>
    

    2 /// 白棋 3 /// 4 public class BlackPieces : ChessPieces 5 { 6 public BlackPieces(string strColour) : base(strColour) 7 { 8 9 } 10 } 11 12 ///

    13 /// 黑棋 14 /// 15 public class WhitePieces : ChessPieces 16 { 17 public WhitePieces(string strColour) : base(strColour) 18 { 19 20 } 21 }

继承自抽象享元类,具体实现其方法。

此实例只是通过构造函数简单的将棋子分成黑白棋子,实际中会有各种属性或方法需要在此类中实现。

  1. 享元工厂角色

        /// <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. 非享元角色

     1     /// <summary>
    

    2 /// 棋盘 3 /// 4 public class ChessBoard 5 { 6 //棋盘编号 7 public int ChessBoardId { get; set; } 8 9 10 //黑方棋手 11 //白方棋手 12 //棋盘棋子布局等等属性 13
    14 ///

    15 /// 初始化棋盘 16 /// 17 public ChessBoard() 18 { 19 //可以通过构造函数 初始化棋盘基础属性 20 } 21 }

非享元部分,也就是不能共享的部分。

棋盘的编号、棋盘对局双方信息和棋盘落子情况等都是每个棋盘独有的,不可共享。

至于棋盘的落子和整体维护可以通过参数注入等形式交给棋子共享对象进行研判和操作,或者直接在棋盘类中进行声明都可以,这就看具体制定的规则了。

  1. 客户端

     1     /// <summary>
    

    2 /// 客户端 3 /// 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 }

总结:

实现享元工厂类时使用单例模式和简单工厂模式,确保对象的唯一性,并提供方法向客户端返回享元对象。

内容
  • Docker-Compose部署Gitlab以及Gitlab配置SMTP邮件服务
    Docker-Compose部署
    2023-12-12
    使用Docker-Compose部署Gitlab.拉取镜像.地址: https://hub.docker.com/r/g
  • 代码审计工具Fortify基本使用
    代码审计工具Fortify基本使
    2023-12-11
    最近接触到一款代码审计的工具 — Fortify SCA and Applications 22.2.0,现就其基本使用
  • c++ function使用
    c++ function使用
    2023-12-11
    一、function介绍.funciotn是从c++11开始支持的特性,使用它需要包含头文件.在cppreference
  • RocketMQ消费者是如何负载均衡的
    RocketMQ消费者是如何负载
    2023-12-09
    摘要:RocketMQ 支持两种消息模式:集群消费( Clustering )和广播消费( Broadcasting )
  • gitlab ci 集成 eslint/prettier/tsc 做代码审查,并使用 eslint 输出作为显示代码质量
    gitlab ci 集成 esl
    2023-12-09
    前言.想自动化一下公司里代码的部分审查,最初想用 reviewdog 的,但是公司的域名基本都在 VPN 中访问的,gi
  • CesiumJS 源码杂谈 - 时间与时钟系统
    CesiumJS 源码杂谈 -
    2023-12-08
    目录.1. 时间的“诞生”.2. 时间的推进.3. Entity API 与 Property API 的更新动力源.4
  • 使用unplugin-auto-import自动导入插件优化vite开发vue3应用
    使用unplugin-auto-
    2023-12-06
    为什么要使用unplugin-auto-import插件?.使用vite编写vue3代码时,使用composition
  • misc刷题
    misc刷题
    2023-12-04
    lsb隐写.引用一段百度内容.> LSB隐写就是修改RGB颜色分量的最低二进制位也就是最低有效位(LSB),而人类的眼睛
  • C#结合OpenCVSharp4使用直方图算法比较图片相似度
    C#结合OpenCVSharp4
    2023-12-04
    C#结合OpenCVSharp4使用直方图算法比较图片相似度.直方图有灰度直方图、颜色直方图,如果是灰度图像,那么就用灰
  • 【AutoHotkey】一种适合敲代码&&可以用左手完成大部分功能的组合键设计
    【AutoHotkey】一种适合
    2023-12-04
    故事一.使用键盘,需要两只手;.使用鼠标,还需要一只手;.总共三只手。.而你,只有两只手.所以,你需要第三只手(bush
  • FlashDuty Changelog 2023-09-07 | 新增深色模式与主题配置
    FlashDuty Change
    2023-12-04
    FlashDuty:一站式告警响应平台,前往此地址免费体验!.FlashDuty.现在已经全面支持了深色模式,这为您提供
  • 1.4 编写简易ShellCode弹窗
    1.4 编写简易ShellCod
    2023-12-02
    在前面的章节中相信读者已经学会了使用Metasploit工具生成自己的ShellCode代码片段了,本章将继续深入探索关
  • 女童裤子
    女童裤子
    2024-01-10
    女童裤子.产品介绍.我们的女童裤子是为年龄在3-12岁之间的女孩设计的。我们的裤子不仅样式多样,而且舒适耐穿,适合学校、
  • 儿童运动服
    儿童运动服
    2023-12-16
    儿童运动服.产品功能.我们的儿童运动服采用高品质的面料和工艺制作而成,具有出色的透气性和舒适性,可以让孩子在运动中保持干
  • 裙子
    裙子
    2023-12-16
    裙子.产品描述.我们的裙子采用高品质的面料制成,款式多样,适合各种场合穿着。无论是休闲的街头漫步,还是正式的商务会议,我
  • 短裤
    短裤
    2023-12-11
    时尚舒适,尽显运动魅力——短裤.产品功能.透气吸汗:采用透气材质制作,有效吸收汗液,让您在运动中保持干爽舒适。.伸缩自如
  • 风衣
    风衣
    2023-12-21
    风衣.产品功能.透气性高,能够有效排出体内热量和汗液,保持身体舒适.防风防水,能够有效阻挡外界风雨,保护身体不受天气影响
  • 儿童外套
    儿童外套
    2023-12-06
    儿童外套.产品功能.我们的儿童外套具有多种功能,包括保暖、防风、防水和舒适。它们采用高质量的面料制成,能够有效地抵御寒冷
  • 外套
    外套
    2023-12-06
    外套.外套是一种经典的服装单品,不仅给人温暖的保护,还可以提升整体的时尚感。我们的外套采用高品质的材料和工艺**而成,既
  • 儿童T恤
    儿童T恤
    2023-12-26
    儿童T恤.儿童T恤是一种专门为儿童设计的上衣,具有舒适、时尚、环保等特点,是孩子们*常穿着的必备单品。.产品功能.儿童T
  • 衬衫
    衬衫
    2023-12-31
    产品介绍:衬衫.产品功能.衬衫是一种适合各种场合穿着的服装,既可以正式地穿在工作场所,也可以搭配牛仔裤穿在休闲场合。.衬
  • 休闲鞋
    休闲鞋
    2024-01-05
    休闲鞋 - 轻松舒适的时尚选择.产品功能.休闲鞋 是一款适合各种活动的多功能鞋,其设计灵感来源于慢生活和自由精神。采用轻