【设计模式】享元

简介: 【设计模式】享元

享元模式介绍





679140-20210817123022031-1709229805.png


享元模式主要在于共享通用对象,减少内存的使用,提升系统的访问效率。而这部分共享对象通常比较耗费内存或者需要查询大量接口或者使用数据库资源,因此统一抽离作为共享对象使用。


在使用此模式过程中,需要使用享元工厂来进行管理这部分独立的对象和共享的对象,避免出现线程安全的问题。


享元模式设计的思想:减少内存的使用提升效率,和之前学习的原型模式通过克隆对象的方式生成复杂对象,减少远程系统的调用。


享元与不可变性


在使用享元模式时,享元对象可在不同情景中是使用,必须确保其状态不可被修改。也就是说享元对象只能由构造函数进行一次性初始化,它不能对其他对象公开其设置器或共有成员变量。


享元工厂


为了更方便的访问各种享元,可以创建一个工厂方法来管理已有享元对象的缓存池。

工厂方法从客户端处接收目标享元对象的内在状态作为参数,如果能提前在缓存池中找到目标享元,则直接返回。如果没有找到,会自动创建一个享元对象,并将其添加到缓存池中。


享元模式的结构


  • 享元模式只是一种优化,主要应用于与大量类似对象同时占用内存相关的内存消耗问题时使用。


  • 享元  类包含原始对象中部分能在多个对象中共享的状态。


  • 情景类 包含原始对象中各不相同的外在状态。情景与享元对象组合在一起就能表示原始对象的全部状态。


  • 客户端  负责计算或存储享元的外在状态。


  • 享元工厂 会对已有享元的缓存池进行管理。


有了工厂后,客户端无需直接创建享元,它们只需调用工厂并向其传递目标享元的一些内在状态即可。工厂会根据参数在之前已创建的享元中进行查找,如果找到满足的直接返回,若没有则进行创建新享元。



仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式。


  • 程序需要生产数量巨大的相似对象


  • 这将耗尽目标设备的所有内存


  • 对象中包含可抽取且能在多个对象间共享的重复状态


实现方式


1、将需要改写为享元的类成员变量拆分为两个部分


  • 内在状态 : 包含不变的,可在许多对象中重复使用的数据的成员变量


  • 外在状态 : 包含每个对象各自不同的情景数据的成员变量


2、保留类中表示内在状态的成员变量,并将其属性设置为不可修改。(这些不变的变量只能通过构造函数进行初始化操作)


3、找到所有使用外在状态成员变量的方法,为在方法中所有的每个成员变量新建一个参数,并使用该参数代替成员变量


4、你可以有选择地创建工厂类来管理享元缓存池,它负责在新建享元时检查已有的享元。如果选择使用工厂,客户端就只能通过工厂来请求享元,它们需要将享元的内在状态作为参数传递给工厂


5、客户端必须存储和计算外在状态的数值,因为只有这样才能调用享元对象的方法。外在状态和引用享元的成员变量可以移动到单独的情景类中。


优点: 如果程序有很多相似的对象,那么可以节省大量的内存。

缺点: 可能牺牲执行速度来换取内存、代码会变的更加复杂。



享元展示了如何生成大量的小型对象,外观模式则展示了如何用一个对象来代表整个子系统。

Demo


  /// <summary>
    /// 享元
    /// </summary>
    public class Flyweight
    {
        private Car _sharedState;
        public Flyweight(Car car)
        {
            this._sharedState = car;
        }
        public void Operation(Car uniqueState) 
        {
            string s = JsonConvert.SerializeObject(this._sharedState);
            string u = JsonConvert.SerializeObject(uniqueState);
            Console.WriteLine("Flyweight:Displaying shared "+s+" and unque "+u+" state");
        }
    }
  /// <summary>
    /// 享元工厂
    /// 思路:提前在缓存池缓存对象,取值时先判断缓存池中取,如没有则创建,同时加入缓存池。
    /// </summary>
    public class FlyweightFactory 
    {
        private List<Tuple<Flyweight,string>> flyweights=new List<Tuple<Flyweight,string>>();
        public FlyweightFactory(params Car[] args)
        {
            foreach (var elem in args)
            {
                flyweights.Add(new Tuple<Flyweight,string>(new Flyweight(elem),this.getKey(elem)));
            }
        }
        public string getKey(Car key) 
        {
            List<string> elements = new List<string>();
            elements.Add(key.Model);
            elements.Add(key.Color);
            elements.Add(key.Company);
            if (key.Owner!=null&& key.Number!=null)
            {
                elements.Add(key.Number);
                elements.Add(key.Owner);
            }
            elements.Sort();
            return string.Join("_",elements);
        }
        public Flyweight GetFlyweight(Car sharedState) 
        {
            string key = this.getKey(sharedState);
            if (flyweights.Where(t=>t.Item2==key).Count()!=0)
            {
                Console.WriteLine("在享元工厂中,缓存中没有数据");
                this.flyweights.Add(new Tuple<Flyweight,string>(new Flyweight(sharedState),key));
            }
            else
            {
                Console.WriteLine("缓冲池中有...");
            }
            return this.flyweights.Where(t => t.Item2 == key).FirstOrDefault().Item1;
        }
        public void listFlyweights() 
        {
            var count = flyweights.Count;
            foreach (var item in flyweights)
            {
                Console.WriteLine(item.Item2);
            }
        }
    }
    public class Car
    {
        public string Owner { get; set; }
        public string Number { get; set; }
        public string Company { get; set; }
        public string Model { get; set; }
        public string Color { get; set; }
    }



     static void Main(string[] args)
        {
            var factory = new FlyweightFactory(
                      new Car { Company = "Chevrolet", Model = "Camaro2018", Color = "pink" },
                new Car { Company = "Mercedes Benz", Model = "C300", Color = "black" },
                new Car { Company = "Mercedes Benz", Model = "C500", Color = "red" },
                new Car { Company = "BMW", Model = "M5", Color = "red" },
                new Car { Company = "BMW", Model = "X6", Color = "white" }
                );
            factory.listFlyweights();
            addCarToPoliceDatabase(factory, new Car {
                Number = "CL234IR",
                Owner = "James Doe",
                Company = "BMW",
                Model = "M5",
                Color = "red"
            });
            addCarToPoliceDatabase(factory, new Car
            {
                Number = "CL234IR",
                Owner = "James Doe",
                Company = "BMW",
                Model = "X1",
                Color = "red"
            });
            factory.listFlyweights();
            Console.ReadKey();
        }
        static void addCarToPoliceDatabase(FlyweightFactory factory, Car car)
        {
            Console.WriteLine("添加一个新Car");
            var flyweight = factory.GetFlyweight(new Car
            {
                Color = car.Color,
                Model = car.Model,
                Company = car.Company
            });
            flyweight.Operation(car);
        }




对于享元工厂需要特意留意,它是先检索缓存池中的数据总情况,发现不是要找的,那么就新创建对象。


目录
相关文章
|
设计模式 缓存 定位技术
设计模式是什么鬼(享元)
设计模式是什么鬼(享元)
设计模式是什么鬼(享元)
|
设计模式 存储 Dart
dart设计模式之外观,享元,代理模式
模式分析 外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。 这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
136 0
|
设计模式 存储
【设计模式】享元模式 实现 ( 实现流程 | 抽象享元类 | 具体享元类 | 享元工厂 | 用户调用 | 代码模板 )
【设计模式】享元模式 实现 ( 实现流程 | 抽象享元类 | 具体享元类 | 享元工厂 | 用户调用 | 代码模板 )
203 0
入门设计模式之享元
版权声明:本文为博主原创文章,未经博主允许不得转载。博客源地址为zhixiang.org.cn https://blog.csdn.net/myFirstCN/article/details/80871456 学习更多设计模式请参考:入门设计模式之汇总篇 享元模式:以共享的方式高效的支持大量的细粒度对象 我们以咖啡为例,一家咖啡店一天卖出几千杯咖啡其实这几千杯也不过是几十种口味。
966 0
|
Java 设计模式 编译器
JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法
JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法 学完我们的java之旅,其实收获还是很多的,但是依然还有很多的知识点需要我们的突破,所以写下这个java进阶之旅的系列,这个系列不会说的那么的基础,主要是对一些高级点的功能进行剖析,所以,一起来看看吧! 一.
1207 0
|
iOS开发 设计模式
|
缓存 Java 编译器
Java高新技术1---增强for循环 ---装箱与拆箱享元设计模式--自己写枚举--可变长度的参数
其实这些知识是我在 看张孝祥老师的Java视频的时候 记录的  ,我可以负责任的说 对于 入门人员来说  这部视频 是 精粹 ,可以 3天内 带你 进入 Java的 另一个 境界 。 话不多说 ,不信 自己去看吧  。
979 0
|
19天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式