Java--设计模式-7-享元模式

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
简介: 享元模式(Flyweight Pattern)就是搞一个缓存池,找对象先在池中找,如果未找到匹配的对象,再创建新对象。通过重用现有的同类对象减少创建对象的数量,以减少内存占用和提高性能。也是属于结构型模式。

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

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

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

代码实现一下:

       参考了知乎一位老师的代码来说明,五子棋游戏的黑白子下棋操作,我觉得很形象:https://zhuanlan.zhihu.com/p/369889407

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

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

结果:

image.png

       通过对比两个对象的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不支持");
    }
  }  
}

结果:


image.png

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
目录
相关文章
|
11天前
|
设计模式 Java 程序员
[Java]23种设计模式
本文介绍了设计模式的概念及其七大原则,强调了设计模式在提高代码重用性、可读性、可扩展性和可靠性方面的作用。文章还简要概述了23种设计模式,并提供了进一步学习的资源链接。
28 0
[Java]23种设计模式
|
27天前
|
设计模式 监控 算法
Java设计模式梳理:行为型模式(策略,观察者等)
本文详细介绍了Java设计模式中的行为型模式,包括策略模式、观察者模式、责任链模式、模板方法模式和状态模式。通过具体示例代码,深入浅出地讲解了每种模式的应用场景与实现方式。例如,策略模式通过定义一系列算法让客户端在运行时选择所需算法;观察者模式则让多个观察者对象同时监听某一个主题对象,实现松耦合的消息传递机制。此外,还探讨了这些模式与实际开发中的联系,帮助读者更好地理解和应用设计模式,提升代码质量。
Java设计模式梳理:行为型模式(策略,观察者等)
|
2月前
|
存储 设计模式 安全
Java设计模式-备忘录模式(23)
Java设计模式-备忘录模式(23)
|
2月前
|
设计模式 存储 算法
Java设计模式-命令模式(16)
Java设计模式-命令模式(16)
|
2月前
|
设计模式 存储 缓存
Java设计模式 - 解释器模式(24)
Java设计模式 - 解释器模式(24)
|
2月前
|
设计模式 安全 Java
Java设计模式-迭代器模式(21)
Java设计模式-迭代器模式(21)
|
2月前
|
设计模式 缓存 监控
Java设计模式-责任链模式(17)
Java设计模式-责任链模式(17)
|
2月前
|
设计模式 运维 算法
Java设计模式-策略模式(15)
Java设计模式-策略模式(15)
|
2月前
|
设计模式 算法 Java
Java设计模式-模板方法模式(14)
Java设计模式-模板方法模式(14)
|
2月前
|
设计模式 存储 安全
Java设计模式-组合模式(13)
Java设计模式-组合模式(13)