1、关于享元模式

  享元模式有点类似于单例模式,都是只生成一个对象被共享使用。享元模式主要目的就是让多个对象实现共享,减少不会要额内存消耗,将多个对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,以此来降低内存的消耗。

2、享元模式结构图

  因为享元模式结构比较复杂,一般结合工厂模式一起使用,在它的结构图中包含了一个享元工厂类。

  在享元模式结构图中包含如下几个角色:

    Flyweight(抽象享元类):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。

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

    UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。

     FlyweightFactory(享元工厂类):享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合(也可以是其他类型的集合),可以结合工厂模式进行设计;当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已创建的实例或者创建一个新的实例(如果不存在的话),返回新创建的实例并将其存储在享元池中。

3、享元模式的实现   

  在享元模式中引入了享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,当用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

  接下来,实现一个登陆的享元模式。

  1、用户类

 /**
* 用户类
* @author 董秀才
*
*/
public class User {
private String username; // 用户名
private String password; // 密码 public User(String username,String password) {
this.username = username;
this.password = password;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
}
}

  2、抽象的登陆者(抽象享元类)

 /**
* 登陆者--抽象享元类
* @author 董秀才
*
*/
public abstract class Loginer { //登陆--享元类公共方法
public abstract void login(User user); }

  3、具体的登陆者(具体享元类)

 /**
* 具体享元类
* @author 董秀才
*
*/
public class ConcreteLoginer extends Loginer{ // 登陆者凭证
private String loginerKey = "";
public ConcreteLoginer(String loginerKey) {
this.loginerKey = loginerKey;
} @Override
public void login(User user) {
System.out.println("登陆者凭证:" + this.loginerKey+",用户名:" + user.getUsername() + ",密码:" + user.getPassword());
} }

  4、具体登陆者的工厂类(享元工厂类)

 /**
* 享元工厂类
* @author 董秀才
*
*/
public class ConcreteLoginerFactory { // map充当对象享元池
private static Map<String,ConcreteLoginer> loginerMap = new HashMap<String, ConcreteLoginer>(); public static ConcreteLoginer getConcreteLoginer(String key) {
// 从享元池中拿 登陆者对象
ConcreteLoginer concreteLoginer = loginerMap.get(key);
// 如果享元池中没有此对象
if(concreteLoginer == null) {
// 创建对象
concreteLoginer = new ConcreteLoginer(key);
// 存到享元池中
loginerMap.put(key, concreteLoginer);
}
// 返回对象
return concreteLoginer;
} // 返回享元池对象数量
public static int getSize() {
return loginerMap.size();
}
}

  5、测试类 

 /**
* 博客测试类
* @author 董秀才
*
*/
public class MainTest { public static void main(String[] args) {
// 去工厂拿对象
ConcreteLoginer concreteLoginer_1 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
concreteLoginer_1.login(new User("董秀才","123456")); ConcreteLoginer concreteLoginer_2 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
concreteLoginer_2.login(new User("董秀才","123456")); ConcreteLoginer concreteLoginer_3 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
concreteLoginer_3.login(new User("董秀才","123456")); // 测试是否是同一个对象
System.out.println("是否是同一个对象:" + ((concreteLoginer_1==concreteLoginer_2)&&(concreteLoginer_2 == concreteLoginer_3))); // 第二登陆者
ConcreteLoginer concreteLoginer_4 = ConcreteLoginerFactory.getConcreteLoginer("博客园");
concreteLoginer_4.login(new User("董才才","654321")); ConcreteLoginer concreteLoginer_5 = ConcreteLoginerFactory.getConcreteLoginer("博客园");
concreteLoginer_5.login(new User("董才才","654321")); ConcreteLoginer concreteLoginer_6 = ConcreteLoginerFactory.getConcreteLoginer("博客园");
concreteLoginer_6.login(new User("董才才","654321")); System.out.println("是否是同一个对象:" + ((concreteLoginer_4==concreteLoginer_5)&&(concreteLoginer_5 == concreteLoginer_6)));
// 工厂类中享元池中对象数量
System.out.println("享元池size:" + ConcreteLoginerFactory.getSize());
} }

  6、运行结果

  

4、总结

  从上面代码和运行结果这可以看到,同一个登陆者登陆时是  "享"  用同一个登陆者对象。在享元对象池中只有两个对象。

  享元模式优点

  享元模式的外部状态相对独立,使得对象可以在不同的环境中被复用(共享对象可以适应不同的外部环境)

  享元模式可共享相同或相似的细粒度对象,从而减少了内存消耗,同时降低了对象创建与垃圾回收的开销

  享元模式缺点

  外部状态由客户端保存,共享对象读取外部状态的开销可能比较大

  享元模式要求将内部状态与外部状态分离,这使得程序的逻辑复杂化,同时也增加了状态维护成本

Java_设计模式之享元模式的更多相关文章

  1. 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)

    原文:乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) 作者:weba ...

  2. python设计模式之享元模式

    python设计模式之享元模式 由于对象创建的开销,面向对象的系统可能会面临性能问题.性能问题通常在资源受限的嵌入式系统中出现,比如智能手机和平板电脑.大型复杂系统中也可能会出现同样的问题,因为要在其 ...

  3. 【GOF23设计模式】享元模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_享元模式.享元池.内部状态.外部状态.线程池.连接池 package com.test.flyweight; /** * ...

  4. 设计模式之享元模式(Flyweight)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于怎样创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  5. Head First设计模式之享元模式(蝇量模式)

    一.定义 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式. ...

  6. 【Unity3D与23种设计模式】享元模式(Flyweight)

    GoF中定义: "使用共享的方式,让一大群小规模对象能更有效地运行" 享元模式一般应用在游戏角色属性设置上 游戏策划需要通过"公式计算"或者"实际测试 ...

  7. Java进阶篇设计模式之七 ----- 享元模式和代理模式

    前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...

  8. Java设计模式之七 ----- 享元模式和代理模式

    前言 在上一篇中我们学习了结构型模式的组合模式和过滤器模式.本篇则来学习下结构型模式最后的两个模式, 享元模式和代理模式. 享元模式 简介 享元模式主要用于减少创建对象的数量,以减少内存占用和提高性能 ...

  9. 【设计模式】享元模式(Flyweight)

    摘要: 1.本文将详细介绍享元模式的原理和实际代码中特别是Android系统代码中的应用. 纲要: 1. 引入享元模式 2. 享元模式的概念及优缺点介绍 3. 享元模式在Android源码中的应用 1 ...

随机推荐

  1. React Native搭建开发环境 之 --走过的坑

    React Native是使用JavaScript和React编写原生移动应用 我的开发平台是基于windows系统,所以只支持android,要是想开发ios系统,那就只能考虑使用沙盒环境 接下来就 ...

  2. request.getRequestDispatcher跳转jsp页面失败

    我在JS里面写了个Ajax,传值给控制器,然后利用request.getRequestDispatcher(),打算跳转至另外一个页面.但是没有跳转成功,运行之后没反应. 在网上搜了资料发现,利用aj ...

  3. EF Core中避免贫血模型的三种行之有效的方法(翻译)

    Paul Hiles: 3 ways to avoid an anemic domain model in EF Core 1.引言 在使用ORM中(比如Entity Framework)贫血领域模型 ...

  4. Linux安装Gradle

    Linux安装Gradle   Gradle 是以 Groovy 语言为基础,面向Java应用为主.基于DSL(领域特定语言)语法的自动化构建工具.在github上,gradle项目很多,有的是gra ...

  5. Vue(day1)

    一.起步 <!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/v ...

  6. 一个老程序员是如何手写Spring MVC的

    人见人爱的Spring已然不仅仅只是一个框架了.如今,Spring已然成为了一个生态.但深入了解Spring的却寥寥无几.这里,我带大家一起来看看,我是如何手写Spring的.我将结合对Spring十 ...

  7. 51Nod-1006 最长公共子序列Lcs

    题目链接 Description 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca ...

  8. Java Jvm运行机制原理

    一:简介 在学习Java虚拟机之前,也就是Jvm之前,我想大家能够带着问题去学习,这样的话,大家学习起来也会比较有所获! 1.Java虚拟机(Jvm)是什么? 2.Java虚拟机是用来干什么的? 3. ...

  9. Android客户端与服务器交互方式-小结

    最近的Android项目开发过程中一个问题困扰自己很长时间,Android客户端与服务器交互有几种方式,最常见的就是webservices和json.要在Android手机客户端与pc服务器交互,需要 ...

  10. IntelliJ IDEA部署tomcat时Edit Configuration Deployment无artifact选项

    IntelliJ IDEA,IntelliJ Idea创建web项目之后在配置web项目时,选择Edit Configration部署Tomcat,Deployment里点击添加无artifact选项 ...