享元模式 - 结构型模式

模式类型:

    Flyweight   享元模式 - 结构型模式 

意图:
    
The intent of this pattern is to use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary.
    运用共享技术有效地支持大量细粒度的对象.
    
概述:
    
享元模式的作用在于节省内存开销,对于系统内存在的大量相似的对象,通过享元的设计方式,可以提取出可共享的部分,将其只保留一份进而节省大量的内存开销。

    并不是所有的对象都适合进行享元设计,它要求对象具有可共享的特征,这些可共享的特征可以做享元设计,对象的可共享特征比例越大,进行享元设计后节省的内存越多。
    注意,对象的不可共享特征不能计入享元设计,所以需要仔细判断区分对象的可共享特征与不可共享特征。


    享元模式的本质是:分离和共享。分离的是对象状态中变与不变的部分,共享的是对象中不变的部分。享元模式的关键之处就是在于分离变与不变,把不变的部分作为享元对象的内部状态,把变化的部分作为外部状态,这样享元对象就可以达到共享的目的,从而减少对象数量,节约内存空间。
    
角色:
    1、抽象享元(Flyweight)角色:享元接口,通过这个接口可以接收并作用于外部状态。通过这个接口传入外部的状态,在享元对象的方法处理中可能会使用这些外部状态数据。
    2、具体享元(ConcreteFlyweight)角色:具体的享元对象,必须是共享的,需要封装Flyweight的内部状态。
    3、非共享的具体享元(UnsharedConcreteFlyweight)角色:非共享的具体享元对象,并不是所有的Flyweight对象都需要共享,非共享的享元对象通常是对共享享元对象的组合对象。
    4、享元工厂(FlyweightFactory)角色:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元对象的接口。
    5、客户端(Client)角色:享元客户端,主要的工作是维持一个对享元对象的引用,计算或存储享元对象的外部状态,也可以访问共享和非共享的享元对象。

模式的应用场景:
    1 一个应用程序使用了大量的对象
    2 完全由于使用大量的对象,造成很大的存储开销 
    3 对象的大多数状态都可变为外部状态
    4 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
    5 应用程序不依赖对象标识.由于Flyweight对象可以被共享,对于概念明显有别的想对象,标识测试将返回真值.

结构图:

 

模式的优缺点:


代码:
网上的实例都差不多,这里还有一个外国网站的(和下面的实例差不多):http://www.tutorialspoint.com/design_pattern/flyweight_pattern.htm

import java.util.HashMap;  import java.util.Map;  class ServiceContext {  private int tableIndex;  private String customerName;  public ServiceContext(int tableIndex, String customerName) {  this.tableIndex = tableIndex;  this.customerName = customerName;  }  public int getTableIndex() {  return tableIndex;  }  public String getCustomerName() {  return customerName;  }  }  interface Drink {  void provideService(ServiceContext serviceContext);  }  class Coffee implements Drink {  public Coffee() {  System.out.println("Coffee is created.");  }  @Override  public void provideService(ServiceContext serviceContext) {  System.out.println("Coffee is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  }  }  class Tea implements Drink {  public Tea() {  System.out.println("Drink is created.");  }  @Override  public void provideService(ServiceContext serviceContext) {  System.out.println("Drink is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  }  }  class Water implements Drink {  public Water() {  System.out.println("Water is created.");  }  @Override  public void provideService(ServiceContext serviceContext) {  System.out.println("Water is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  }  }  class DrinkFactory {  private Map<String, Drink> drinks = new HashMap<>();  public Drink createDrink(String type) {  Drink drink = drinks.get(type);  if (drink == null) {  // 以下可以考虑抽象工厂模式实现以符合开闭原则,也可以使用反射  if (type.equals("Water")) {  drink = new Water();  } else if (type.equals("Tea")) {  drink = new Tea();  } else if (type.equals("Coffee")) {  drink = new Coffee();  }  drinks.put(type, drink);  }  return drink;  }  }  public class WaiterTest {  public static void main(String[] args) {  String[] types = {"Water", "Tea", "Coffee"};  DrinkFactory drinkFactory = new DrinkFactory();  for (int i = 1; i <= 9; i++) {  Drink drink = drinkFactory.createDrink(types[i % 3]);// Drink 可共享特征 在 DrinkFactory 内部实现享元  ServiceContext serviceContext = new ServiceContext(i, "Sir" + i);// 服务细节为不可共享特征,不能享元  drink.provideService(serviceContext);//外部特征,不可共享特征,保证调用过程不会影响下次调用。  
            }  }  }  

输出:

Drink is created.  
Drink is serving for table 1 customer Sir1  
Coffee is created.  
Coffee is serving for table 2 customer Sir2  
Water is created.  
Water is serving for table 3 customer Sir3  
Drink is serving for table 4 customer Sir4  
Coffee is serving for table 5 customer Sir5  
Water is serving for table 6 customer Sir6  
Drink is serving for table 7 customer Sir7  
Coffee is serving for table 8 customer Sir8  
Water is serving for table 9 customer Sir9

可以看出:在9次的服务过程中,饮品只创建了三次,一种饮品都仅仅创建了一次,减小了很多内存开销,服务可以很好的进行。
这就是享元模式的精髓,但务必注意区分出可共享与不可共享部分,保证不可共享部分在使用之后不会影响下次使用,即不会改变可共享部分。

相关模式:
    享元模式与单例模式:两者可以组合使用。享元模式中的享元工厂完全可以实现为单例,另外,享元工厂中缓存的享元对象,都是单例实例,可以看成是单例模式的一种变形控制,在享元工厂中来单例享元对象。
    享元模式与组合模式:两者可以组合使用。在享元模式中,存在不需要共享软件的享元实现,这些不需要共享的享元通常是对共享的享元对象的组合对象。换句话来说,就是通过将将两种模式组合使用,可以实现更复杂的对象层次结构。
    享元模式与状态模式:两者可以组合使用。可以使用享元模式来共享状态模式中的状态对象。通常在状态模式中,会存在数量很大的,细粒度的状态对象,而且它们基本上可以重复使用的,都是用来处理某一个固定的状态的,它们需要的数据通常都是由上下文传入,也就是变化部分都被分离出去呢,所以可以用享元模式来实现这些状态对象呢。
    享元模式与策略模式:两者可以组合使用。也可以使用享元来实现策略模式中的策略对象。和状态模式一样,策略模式中也存在大量细粒度的策略对象,它们需要的数据同样也是从上下文传入的,因而可以通过享元模式来实现这些策略对象。

 

所有模式:
     创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
    行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
    补充模式:空对象模式

 

原文地址:https://blog.csdn.net/paincupid/article/details/46896653

 

转载于:https://www.cnblogs.com/tartis/p/9288750.html

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

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

相关文章

前端试题(四)

1. vue过滤器使用场景 2. v-on绑定多个方法 <p v-on"{click:dbClick,mousemove:MouseClick}"></p>一个事件绑定多个函数&#xff1a; <p click"one(),two()">点击</p>3. 在菜单结构不确定时&#xff0c;前端如何动态渲染 树形…

http --- 用于HTTP调试的最小型Perl Web 服务器

下面的程序是个很有用户的诊断工具,可以用来调试与客户端和代理的交互情况. 该程序 首先会等待HTTP连接,只有收到请求报文,就会将报文打印在屏幕上,然后等待用户输入一条响应报文,并将其回送给客户端. #! /usr/bin/perl use Socket; use Carp; use FileHandle;# (1) use prot …

Mysql - 安装与配置

1、下载安装包 > https://www.mysql.com/downloads/ 2、双击安装&#xff0c;点击Install MySQL Products > 3、Skip 打钩&#xff0c;Next下一步 > 4、选择Server only&#xff1a;只选择安装服务端&#xff0c;根据个人喜好更改安装路径和数据保存路径…

4084:拓扑排序

题目链接&#xff1a;http://bailian.openjudge.cn/practice/4084/ 总时间限制: 1000ms 内存限制: 65536kB描述给出一个图的结构&#xff0c;输出其拓扑排序序列&#xff0c;要求在同等条件下&#xff0c;编号小的顶点在前。 输入若干行整数&#xff0c;第一行有2个数&#xff…

廖雪峰git教程学习

廖雪峰git教程 git – Linus在2周内用c写的 1.1 基本概念 版本控制系统&#xff0c;追踪文本文件的改动&#xff0c;文件、视频等二进制文件则不可追踪&#xff08;微软的word也是二进制文件&#xff09;HEAD 指向当前分支&#xff0c;表示当前版本&#xff08;最新的提交&am…

操作系统 --- 进程和管程的不同

1.进程定义的是私有数据结构PCB,管程定义的是公共数据结构,如消息队列等; 2.进程是由顺序程序执行有关操作,而管程主要是进行同步操作和初始化操作; 3.设置进程的目的在于实现系统的并发行,而管程的设置则是解决共享资源的互斥使用问题; 4.进程通过调用管程中的过程对共享数据结…

JCO 自定义DestinationDataProvider

要让JAVA程序能访问SAP系统&#xff0c;一般通过SAP JCO接口进行通讯&#xff0c;在获取到SAP的连接时需求提供一些连接参数&#xff0c;这些参数在最新的 JCO 3.0 中需要被保存到一个带有扩展名.jcoDestination的文件中&#xff0c;这个文件同时被保存在应用程序的安装目录中。…

android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser

android 从4.3系统开始可以连接BLE设备&#xff0c;这个大家都知道了。iOS是从7.0版本开始支持BLE。android 进入5.0时代时&#xff0c;开放了一个新功能&#xff0c;手机可以模拟设备发出BLE广播&#xff0c; 这个新功能其实是 对标于 iOS系统的手机模拟iBeacon设备。先介绍一…

前端后台管理系统梳理

再梳理一遍 一、商品后台管理系统 1. 功能 1.1 服务端情况 开启了CORS跨域支持需要授权的 API &#xff0c;必须在请求头中使用 Authorization 字段提供token 令牌&#xff08;axios拦截器&#xff09;baseUrl&#xff0c;接口地址&#xff1a;http://localhost:8888/api/…

操作系统 --- 使用套接字进行网络通信

一个套接字就是一个通信标识类型的数据结构,包含了通信目的的地址、通信使用的端口号、通信网络的传输协议、进程所在的网络地址,以及针对客户或服务器程序提供的不同系统调用等,是进程通信和网络通信的基本构件。套接字是为客户/服务器模型而设计的,通常分为以下两类: 1.基于…

构造器执行顺序

转载于:https://www.cnblogs.com/a6948076/p/8045801.html

Java08-java语法基础(七)构造方法

Java08-java语法基础&#xff08;七&#xff09;构造方法 一、构造方法 1、什么是构造方法&#xff1f; 构造方法&#xff08;类方法&#xff09;是一个方法名和类名相容的特殊的成员方法。 2、构造方法的作用&#xff1f; 当使用new关键字创建一个对象时&#xff0c;为新建对象…

安装mysql8.0.20,报错“找不到VCRUNTIME140_1.dll”

写在最前&#xff0c;指令集合 以管理员身份运行cmd mysql -uroot -p 【进入】mysql mysql > exit 【退出】 net stop mysql 【暂停】 net start mysql 【启动】 mysql -u root -p&#xff08;命令后输入临时密码&#xff0c;进入mysql&#xff09; ALTER USER USER() …

操作系统 --- 线程与进程的比较

如果说,在操作系统中引入进程的目的是为了使多个程序能并发执行,以提高资源利用率和系统吞吐量,那么在操作系统中再引入线程,则是为了减少程序在并发执行时所付出的时空开销,使OS(操作系统)具有更好的并发性… 我们再回顾一下进程的两个基本属性: 1.进程是一个可拥拥有资源的独…

24种吸引人的营销文章标题写法,总有一个适合你!

在如今信息爆炸的互联网时代下&#xff0c;如何提高提高文章的阅读(新闻稿、软文宣传稿、微信公众号)&#xff0c;成为从业者们共同研究的课题?首先你得有一个足够吸引的标题&#xff0c;尤其是定向推送的时候&#xff0c;这将是由一个质变带来量变的过程。小编虽然不提倡标题…

[js] 处理字符串换行造成的json解析失败

需求&#xff1a;从数据库某个字段取出字符串出来&#xff0c;转为json&#xff0c;结果发现报错为 解析失败&#xff0c;发现是因为取出的字符串换行导致&#xff0c;现在需要将字符串里面的换行替换为&#xff0c;使字符串可依成功解析成json对象。 技术&#xff1a;依靠repl…

使用mockjs模拟数据

一、安装 简单粗暴 npm install mockjs 二、引入 CommonJS引入 let Mock require(mockjs) let userInfo Mock.mock({data: {responseCode: 200,responseMessage: success,userMessage: {name: "cname",email: "email",msg: cparagraph(2)}} })或者ES…

angular --- ngDialog关闭当前层

今天做项目,使用ngDialog 弹出了一层,并且在弹出层上又弹出了第二层. 现在想点击确定按钮关闭第二层. 使用以前的ngDialog.close()会关闭掉全部ngDialog.open方法弹出来的层. 在网上查了一堆,找了好多,最后发现就一句话.$scope.closeThisDialog(); 注意, 要在controller:中传递…

lodash源码分析之compact中的遍历

小时候&#xff0c; 乡愁是一枚小小的邮票&#xff0c; 我在这头&#xff0c; 母亲在那头。 长大后&#xff0c;乡愁是一张窄窄的船票&#xff0c; 我在这头&#xff0c; 新娘在那头。 后来啊&#xff0c; 乡愁是一方矮矮的坟墓&#xff0c; 我在外头&#xff0c; 母亲在里头。…

[HAOI2008]移动玩具

这又是一道神奇的搜索题。。。只要记录每种状态。。。然后暴力判断这种状态往后一步的情况。。。 广搜出最优解即可。。。 呆码&#xff1a; #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std;int dx[5]{0…