设计模式-7-享元模式

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 MongoDB,通用型 2核4GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 享元模式(Flyweight Pattern)就是搞一个缓存池,找对象先在池中找,如果未找到匹配的对象,再创建新对象。通过重用现有的同类对象减少创建对象的数量,以减少内存占用和提高性能。也是属于结构型模式。

  享元模式(Flyweight Pattern)就是搞一个缓存池,找对象先在池中找,如果未找到匹配的对象,再创建新对象。通过重用现有的同类对象减少创建对象的数量,以减少内存占用和提高性能。也是属于结构型模式。

       专业点说,享元模式就是运用共享技术有效地支持大量细粒度的对象。

       在Java的JDK中,提供了一个字符串缓存池,我们在new一个字符串对象的时候,程序会自动去池中查找,如果有就返回,没有就再去new,然后放入缓存池中。还有线程池,也是运用享元模式的典型案例。

代码实现一下:

       参考了知的乎一位老师的代码来说明,五子棋游戏的黑白子下棋操作,我觉得很形象。

一、五子棋下棋操作代码:

1.新建一个接口,用来进行对象的共有操作packagecom.xing.design.flyweight.chess;
/***  共享对象通用的接口 黑棋和白棋都通过这个方法画到棋盘上* @author xing*/publicinterfaceChess {
//下棋操作voiddraw(intx,inty);
}
2.分别实现不同的子类(黑棋和白棋)
packagecom.xing.design.flyweight.chess;
/*** 黑棋* @author xing*/publicclassBlackChessimplementsChess {
// 共性 圆形privatefinalStringsharp="圆形";
publicBlackChess() {
System.out.println("new一个新黑棋对象");
    }
@Overridepublicvoiddraw(intx, inty) {
System.out.println("黑色"+sharp+"棋子置于"+x+","+y+"处");
  }
}
packagecom.xing.design.flyweight.chess;
publicclassWhiteChessimplementsChess {
// 内部状态 圆形privatefinalStringsharp="圆形";
publicWhiteChess() {
System.out.println("new一个新白棋对象");
    }
@Overridepublicvoiddraw(intx, inty) {
System.out.println("白色"+sharp+"棋子置于"+x+","+y+"处");
  }
}
注意这里的圆形,这个是每个对象都有的内部状态。3.上面对象有了,再建立一个工厂来生成对象packagecom.xing.design.flyweight.chess;
importjava.util.HashMap;
importjava.util.Map;
/***  共享对象工厂 负责提供共享对象,客户端不应该直接实例化棋子对象,而应该使用此工厂来获取。因为我们分了黑白两类对象,所以这里使用Color为key的map来存储共享对象。* @author xing*/publicclassChessFactory {
/*** 缓存池*/privatestaticfinalMap<String, Chess>chessMap=newHashMap<>();
/*** 根据唯一的外部状态获取对象* @param color 外部状态 黑色/白色* @return*/publicstaticChessgetChess(Stringcolor) {
System.out.println("此时对象缓存池中对象->"+chessMap);
Chesschess=chessMap.get(color);
if (chess==null) {
chess=color.equals("白色") ?newWhiteChess() : newBlackChess();
chessMap.put(color, chess);
        }else {
System.out.println("已经有"+color+"棋子对象啦,不new了,直接用缓存池中的");
        }
returnchess;
    }
}
这就是核心代码了,我们必须通过这个工厂来获取的对象。4.客户端测试一下packagecom.xing.design.flyweight.chess;
importjava.util.ArrayList;
importjava.util.List;
/*** 客户端* @author xing*/publicclassFlyweightClient {
publicstaticvoidmain(String[] args) {
// 棋盘List<Chess>chessList=newArrayList<>();
//下黑子ChessbackChess1=ChessFactory.getChess("黑色");
backChess1.draw(2, 5);
chessList.add(backChess1);
//下白子ChesswhiteChess=ChessFactory.getChess("白色");
whiteChess.draw(3, 5);
chessList.add(whiteChess);
//下黑子ChessbackChess2=ChessFactory.getChess("黑色");
backChess2.draw(2, 6);
chessList.add(backChess2);
//下白子ChesswhiteChess2=ChessFactory.getChess("白色");
backChess2.draw(3, 8);
chessList.add(whiteChess2);
System.out.println(String.format("backChess1:%d | backChess2:%d | whiteChess:%d  | whiteChess2:%d",
backChess1.hashCode(), backChess2.hashCode(), whiteChess.hashCode(), whiteChess2.hashCode()));       
System.out.println("生成的持久化对象个数->"+chessList.size());
    }
}

结果。。。

       通过对比两个对象的hashCode,我们发现确实是同一个对象,下了四个棋子,只new了两个对象哈!

再来一个应用场景:

二、缓存一个连接池

换一个应用场景,我们要用享元模式来搞一个缓存池,我们要怎么来实现呢?1.连接对象抽象一个接口,方便以后增加连接类型packagecom.xing.design.flyweight.pool;
/***  线程对象公共操作* @author xing* @createTime*/publicinterfaceConnect {
/*** 连接*/publicvoidconnect();
}
2.两个实现:mysqlpackagecom.xing.design.flyweight.pool;
/***  Mysql连接对象* @author xing*/publicclassConnectMysqlimplementsConnect{
/**连接地址 */privateStringurl;
publicStringgetUrl() {
returnurl;
  }
publicvoidsetUrl(Stringurl) {
this.url=url;
  }
publicConnectMysql() {
System.out.println("new了一个Mysql连接对象");
  }
@Overridepublicvoidconnect() {
System.out.println("Mysql连接成功,连接信息:【"+url+"】");
  }
}
oraclepackagecom.xing.design.flyweight.pool;
/***  Oracle连接对象* @author xing*/publicclassConnectOracleimplementsConnect{
/**连接地址 */privateStringurl;
/**用户名 */privateStringuserName;
/**密码 */privateStringpassWord;
publicStringgetUrl() {
returnurl;
  }
publicvoidsetUrl(Stringurl) {
this.url=url;
  }
publicStringgetUserName() {
returnuserName;
  }
publicvoidsetUserName(StringuserName) {
this.userName=userName;
  }
publicStringgetPassWord() {
returnpassWord;
  }
publicvoidsetPassWord(StringpassWord) {
this.passWord=passWord;
  }
publicConnectOracle() {
System.out.println("new了一个Oracle连接对象");
  }
@Overridepublicvoidconnect() {
System.out.println("Oracle连接成功,连接信息:【地址:"+url+"|用户名:"+userName+"|密码:"+passWord+"】");
  }
}
3.搞个工厂,核心代码packagecom.xing.design.flyweight.pool;
importjava.util.HashMap;
importjava.util.Map;
/***  工厂生成连接对象* @author xing*/publicclassConnectFacatory {
/*** 连接池*/privatestaticfinalMap<String, Connect>chessMap=newHashMap<>();
publicstaticConnectgetConnect(Stringtype) {
Connectconnect=chessMap.get(type);
if(connect!=null) {
System.out.println("池中已有"+type+"对象,直接使用");
returnconnect;
    }
switch (type) {
case"mysql":
connect=newConnectMysql();
chessMap.put(type, connect);
break;
case"oracle":
connect=newConnectOracle();
chessMap.put(type, connect);
break;
default:
System.out.println("暂只支持mysql、oracle连接"+type+"是不可用的连接类型");
connect=null;
    }
returnconnect;
  }
}
4.demo使用验证packagecom.xing.design.flyweight.pool;
publicclassConnectDemo {
publicstaticvoidmain(String[] args) {
System.out.println("--------------------------------mysql--------------------------------");
ConnectMysqlmysql1= (ConnectMysql) ConnectFacatory.getConnect("mysql");
mysql1.setUrl("http//127.0.0.1/xing");
mysql1.connect();
ConnectMysqlmysql2= (ConnectMysql) ConnectFacatory.getConnect("mysql");
mysql2.setUrl("http//127.0.0.2/hua");
mysql2.connect();
if(mysql1.hashCode() ==mysql2.hashCode()) {
System.out.println("mysql1->hash码【"+mysql1.hashCode()+"】和mysql2->hash码【"+mysql1.hashCode()+"】是同一个对象");
    }
System.out.println("--------------------------------oracle--------------------------------");
ConnectOracleoracle1= (ConnectOracle) ConnectFacatory.getConnect("oracle");
oracle1.setUrl("http//127.0.0.1/ora");
oracle1.setUserName("root");
oracle1.setPassWord("123");
oracle1.connect();
ConnectOracleoracle2= (ConnectOracle) ConnectFacatory.getConnect("oracle");
oracle2.setUrl("http//127.0.0.1/ora");
oracle2.setUserName("root");
oracle2.setPassWord("root");
oracle2.connect();
ConnectOracleoracle3= (ConnectOracle) ConnectFacatory.getConnect("oracle");
oracle3.setUrl("http//127.0.0.1/jing");
oracle3.setUserName("cang");
oracle3.setPassWord("123");
oracle3.connect();
System.out.println("oracle1的hashCode:"+oracle1.hashCode());
System.out.println("oracle2的hashCode:"+oracle2.hashCode());
System.out.println("oracle3的hashCode:"+oracle3.hashCode());
System.out.println("--------------------------------mongoDB--------------------------------");
ConnectmongoDB=ConnectFacatory.getConnect("mongoDB");
if(mongoDB==null) {
System.out.println("呐,mongoDB不支持");
    }
  }  
}

OK!


总结:

       享元模式就是将用过的对象用HashMap作为缓存池存储,下次用的时候用唯一的外部状态(type)去缓存池取,取不到再重新new,用这样的模式来大大减少相同对象的初始化,减少内存开支,缺点是提高了系统复杂度,核心代码是必须要有一个工厂类来控制对象的创建。

END

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
1月前
|
设计模式 存储 Java
23种设计模式,享元模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享技术有效地支持大量细粒度对象的重用。这个模式在处理大量对象时非常有用,特别是当这些对象中的许多实例实际上可以共享相同的状态时,从而可以减少内存占用,提高程序效率
36 4
|
7月前
|
设计模式 存储 缓存
结构型设计模式07-享元模式
结构型设计模式07-享元模式
20 0
|
5月前
|
设计模式 存储 安全
二十三种设计模式全面解析-享元模式(Flyweight Pattern)详解:构建高效共享的对象结构
二十三种设计模式全面解析-享元模式(Flyweight Pattern)详解:构建高效共享的对象结构
|
5月前
|
设计模式
二十三种设计模式全面解析-组合模式与享元模式的结合应用:实现对象的共享和高效管理
二十三种设计模式全面解析-组合模式与享元模式的结合应用:实现对象的共享和高效管理
|
7月前
|
设计模式 存储 Java
【设计模式——学习笔记】23种设计模式——享元模式Flyweight(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——享元模式Flyweight(原理讲解+应用场景介绍+案例介绍+Java代码实现)
29 0
|
22天前
|
设计模式 存储 Java
小谈设计模式(27)—享元模式
小谈设计模式(27)—享元模式
|
2月前
|
设计模式 缓存 Java
设计模式之享元模式
设计模式之享元模式
|
2月前
|
设计模式 存储 缓存
【设计模式】享元模式
【设计模式】享元模式
|
4月前
|
设计模式 存储 缓存
聊聊Java设计模式-享元模式
享元(Flyweight)模式:顾名思义就是**被共享的单元**。意图是复用对象,节省内存,提升系统的访问效率。比如在红白机冒险岛游戏中的背景花、草、树木等对象,实际上是可以多次被不同场景所复用共享,也是为什么以前的游戏占用那么小的内存,却让我们感觉地图很大的原因。
17 3
聊聊Java设计模式-享元模式
|
9月前
|
设计模式 存储 缓存
享元模式【Java设计模式】
享元模式【Java设计模式】
31 0
享元模式【Java设计模式】