设计模式之享元

享元模式介绍

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

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

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

享元与不可变性

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

享元工厂

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

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

享元模式的结构

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

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

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

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

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

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

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

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

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

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

实现方式

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);}

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

小寄语

人生短暂,我不想去追求自己看不见的,我只想抓住我能看的见的。

我是阿辉,感谢您的阅读,如果对你有帮助,麻烦点赞、转发  谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

真正拉开人与人之间的差距是什么?

全世界只有3.14 % 的人关注了青少年数学之旅身边总有些人看上去很轻松&#xff0c;不仅在工作中游刃有余&#xff0c;还知识渊博&#xff0c;对各种事情有自己的思考。这样的人一定是天生的学霸吧。其实学习不一定要在教室里从一本书的第一页开始看&#xff0c;学习可以很轻松。…

[导入]【翻译】WF从入门到精通(第八章):调用外部方法及工作流

摘要: 学习完本章&#xff0c;你将掌握&#xff1a; 1.创建并调用你的工作流外部的本地数据服务 2.理解怎样使用接口来为宿主进程和你的工作流之间进行通信。 3.使用设计的外部方法在你的工作流和宿主应用程序之间传输数据。 4.在一个正执行的工作流中调用其它工作流 阅读全文…

(译)Windsor入门教程---第三部分 编写第一个Installer

原文&#xff1a;http://docs.castleproject.org/Windsor.Windsor-tutorial-ASP-NET-MVC-3-application-To-be-Seen.ashx 简介 在第二部分我们创建了控制器工厂。现在我们要把我们的控制器交给Windsor来管理。 Installer Windsor有一个专门的类installer.cs&#xff0c;用来向容…

在 ASP.NET Core 中使用 Serilog 使用 Fluentd 将日志写入 Elasticsearch

在 ASP.NET Core 中使用 Serilog 使用 Fluentd 将日志写入 Elasticsearch原文来自&#xff1a;https://andrewlock.net/writing-logs-to-elasticsearch-with-fluentd-using-serilog-in-asp-net-core/对于在 Kubernetes 中运行的应用程序&#xff0c;将日志消息存储在一个中心位…

2021年度最全面JVM虚拟机,类加载过程与类加载器

前言 类装载器子系统是JVM中非常重要的部分&#xff0c;是学习JVM绕不开的一关。 一般来说&#xff0c;Java 类的虚拟机使用 Java 方式如下&#xff1a; Java 源程序&#xff08;.java 文件&#xff09;在经过 Java 编译器编译之后就被转换成 Java 字节代码&#xff08;.class …

做生意最重要的诚信呢??? | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源网络&#xff0c;侵权删&#xff09;

面试避坑手册之 Java字节流和字符流总结IO流!

从接收输入值说起 在日常的开发应用中&#xff0c;有时候需要直接接收外部设备如键盘等的输入值&#xff0c;而对于这种数据的接收方式&#xff0c;我们一般有三种方法&#xff1a;字节流读取&#xff0c;字符流读取&#xff0c;Scanner 工具类读取。 字节流读取 直接看一个…

这家AI公司用面具破解中国人脸识别系统!微信、支付宝、火车站无一幸免

全世界只有3.14 % 的人关注了青少年数学之旅据外媒报道&#xff0c;一家人工智能公司Kneron用一个特制的3D面具&#xff0c;成功欺骗了包括支付宝和微信在内的诸多人脸识别支付系统&#xff0c;完成了购物支付程序。他们用同样的方式甚至进入了中国的火车站。现如今&#xff0c…

coolite TreeNode NodeClick传id到后台的方法

重点如下&#xff1a; 1 <AjaxEvents>2 <Click OnEvent"PanelTree_Click" >3 <EventMask ShowMask"true" Msg"正在执行,请稍后" />4 <E…

使用JavaScript实现页面选项自动添加行以及删除行 javaweb

2019独角兽企业重金招聘Python工程师标准>>> <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <% String path request.getContextPath(); String basePath request.getScheme()"://"reques…

C#基础知识之base、this、new、override、abstract梳理

一、Base关键词的几种用法base重要用于OOP的多态上&#xff0c;base 关键字用于在派生类中实现对基类公有或者受保护成员的访问&#xff0c;但是只局限在构造函数、实例方法和实例属性访问器中1、base调用基类构造函数using System;namespace BaseDemo {class Program{static v…

班主任老师推荐这些优质的教育号,建议家长们多阅读!

全世界只有3.14 % 的人关注了青少年数学之旅推荐几个教育类学习号让孩子少走弯路&#xff0c;为孩子成长保驾护航&#xff01;长按二维码&#xff0c;选择【识别图中二维码】关注理想父母 lixiangfumu&#xff08;长按二维码识别关注&#xff09;关注理由&#xff1a;面向家长…

学妹问我Java枚举类与注解,我直接用这个搞定她!

很多人问我学妹长什么样&#xff0c;不多说 上图吧&#xff01; 学妹问我Java枚举类与注解&#xff0c;我直接一篇文章搞定&#xff01;一、枚举类① 自定义枚举类② enum关键字定义枚举类③ enum 枚举类的方法④ enum 枚举类实现接口二、注解① 生成文档相关注解②注解在编译…

设计模式之代理

代理模式介绍啥是代理模式&#xff1f;代理模式 是一种结构型设计模式&#xff0c;让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问&#xff0c;并允许在将请求提交给对象前后进行一些处理。其实说通俗点&#xff0c;就好比我们平时生活中的购买机票&#xff…

轮子,辛苦你了。 | 今日最佳

全世界只有3.14 % 的人关注了青少年数学之旅&#xff08;图源帅哥李坏的朋友圈&#xff0c;侵权删&#xff09;

这次牛逼了,面试字节被问LinkedList原理了!手足无措啊

概述 LinkedList底层是基于链表实现。链表没有长度限制&#xff0c;内存地址不需要固定长度&#xff0c;也不需要是连续的地址来进行存储&#xff0c;只需要通过引用来关联前后元素即可完成整个链表的连续。所以链表的优点就是添加删除元素比较快&#xff0c;只需要移动指针&a…

[WP8.1UI控件编程]Windows Phone自定义布局规则

3.2 自定义布局规则 上一节介绍了Windows Phone的系统布局面板和布局系统的相关原理&#xff0c;那么系统的布局面板并不一定会满足所有的你想要实现的布局规律&#xff0c;如果有一些特殊的布局规律&#xff0c;系统的布局面板是不支持&#xff0c;这时候就需要去自定义实现一…

聊聊编程语言的选择

我适合学什么编程语言呢&#xff1f;大家好&#xff0c;我是鱼皮&#xff0c;今天聊聊编程语言的选择问题&#xff0c;通过对 10 主流编程语言的特点、优劣、应用场景、发展前景等简单分析&#xff0c;希望帮还在迷茫的小伙伴们选择最适合自己的语言去学习。编程语言选择本文大…

IIS6文件权限不对触发了Windows身份认证问题解决方法

今天在iis上调试程序的时候突然发现需要登录: 通过csdn提问得知可能是权限设置有问题于是设置了下internet来宾用户: 结果问题没有解决.后来想想应该不是问题,因为我在自己机器上调试用的是Everyone权限,应该都可以访问. 于是我又去用户管理中重置internet来宾用户密码: 重置In…

C++ Exercises(十五)--排序算法的简单实现

structNode {//队列结点 int data; struct Node* pNext;};classCQueue{//队列类(带头结点&#xff09;public: CQueue(void); ~CQueue(void); bool isEmpty()const;//是否为空 void EnQueue(int num);//入队列 int DeQueue();//出队列 int Front()cons…