开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第九天,点击查看活动详情
PS:已经更文多少天,N就写几。一定要写对文案,否则文章不计入在内;模板句子需要带超链接。
享元模式(Flyweight Pattern)就是搞一个缓存池,找对象先在池中找,如果未找到匹配的对象,再创建新对象。通过重用现有的同类对象减少创建对象的数量,以减少内存占用和提高性能。也是属于结构型模式。
专业点说,享元模式就是运用共享技术有效地支持大量细粒度的对象。
在Java的JDK中,提供了一个字符串缓存池,我们在new一个字符串对象的时候,程序会自动去池中查找,如果有就返回,没有就再去new,然后放入缓存池中。还有线程池,也是运用享元模式的典型案例。
代码实现一下:
一、五子棋下棋操作代码:
1.新建一个接口,用来进行对象的共有操作
package com.xing.design.flyweight.chess;
/** * 共享对象通用的接口 黑棋和白棋都通过这个方法画到棋盘上 * @author xing */public interface Chess {//下棋操作void draw(int x,int y);}
2.分别实现不同的子类(黑棋和白棋)
package com.xing.design.flyweight.chess;
/** * 黑棋 * @author xing */public class BlackChess implements Chess {// 共性 圆形 private final String sharp = "圆形";public BlackChess() { System.out.println("new一个新黑棋对象"); }@Overridepublic void draw(int x, int y) { System.out.println("黑色"+sharp+"棋子置于"+x+","+y+"处"); }}
package com.xing.design.flyweight.chess;
public class WhiteChess implements Chess {// 内部状态 圆形private final String sharp = "圆形";public WhiteChess() { System.out.println("new一个新白棋对象"); }@Overridepublic void draw(int x, int y) { System.out.println("白色"+sharp+"棋子置于"+x+","+y+"处"); }}
注意这里的圆形,这个是每个对象都有的内部状态。
3.上面对象有了,再建立一个工厂来生成对象
package com.xing.design.flyweight.chess;
import java.util.ArrayList;import java.util.List;
/** * 客户端 * @author xing */public class FlyweightClient {
public static void main(String[] args) {// 棋盘 List<Chess> chessList = new ArrayList<>();
//下黑子 Chess backChess1 = ChessFactory.getChess("黑色"); backChess1.draw(2, 5); chessList.add(backChess1);
//下白子 Chess whiteChess = ChessFactory.getChess("白色"); whiteChess.draw(3, 5); chessList.add(whiteChess);
//下黑子 Chess backChess2 = ChessFactory.getChess("黑色"); backChess2.draw(2, 6); chessList.add(backChess2);
//下白子 Chess whiteChess2 = 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.连接对象抽象一个接口,方便以后增加连接类型
package com.xing.design.flyweight.pool;
/** * 线程对象公共操作 * @author xing * @createTime */public interface Connect {/** * 连接 */public void connect();}
2.两个实现:
mysql
package com.xing.design.flyweight.pool;
/** * Oracle连接对象 * @author xing */public class ConnectOracle implements Connect{/**连接地址 */private String url;/**用户名 */private String userName;/**密码 */private String passWord;public String getUrl() {return url; }public void setUrl(String url) {this.url = url; }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; }public ConnectOracle() { System.out.println("new了一个Oracle连接对象"); } @Overridepublic void connect() { System.out.println("Oracle连接成功,连接信息:【地址:"+url+"|用户名:"+userName+"|密码:"+passWord+"】"); }}
3.搞个工厂,核心代码
package com.xing.design.flyweight.pool;
import java.util.HashMap;import java.util.Map;
/** * 工厂生成连接对象 * @author xing */public class ConnectFacatory {
/** * 连接池 */private static final Map<String, Connect> chessMap = new HashMap<>();
public static Connect getConnect(String type) { Connect connect = chessMap.get(type);if(connect != null) { System.out.println("池中已有"+type+"对象,直接使用");return connect; }switch (type) {case "mysql": connect = new ConnectMysql(); chessMap.put(type, connect);break;case "oracle": connect = new ConnectOracle(); chessMap.put(type, connect);break;default: System.out.println("暂只支持mysql、oracle连接"+type+"是不可用的连接类型"); connect = null; }return connect; }}
4.demo使用验证
package com.xing.design.flyweight.pool;
public class ConnectDemo {
public static void main(String[] args) { System.out.println("--------------------------------mysql--------------------------------"); ConnectMysql mysql1 = (ConnectMysql) ConnectFacatory.getConnect("mysql"); mysql1.setUrl("http//127.0.0.1/xing"); mysql1.connect(); ConnectMysql mysql2 = (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--------------------------------"); ConnectOracle oracle1 = (ConnectOracle) ConnectFacatory.getConnect("oracle"); oracle1.setUrl("http//127.0.0.1/ora"); oracle1.setUserName("root"); oracle1.setPassWord("123"); oracle1.connect(); ConnectOracle oracle2 = (ConnectOracle) ConnectFacatory.getConnect("oracle"); oracle2.setUrl("http//127.0.0.1/ora"); oracle2.setUserName("root"); oracle2.setPassWord("root"); oracle2.connect(); ConnectOracle oracle3 = (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--------------------------------"); Connect mongoDB = ConnectFacatory.getConnect("mongoDB");if(mongoDB == null) { System.out.println("呐,mongoDB不支持"); } } }
结果:
OK!
总结:
享元模式就是将用过的对象用HashMap作为缓存池存储,下次用的时候用唯一的外部状态(type)去缓存池取,取不到再重新new,用这样的模式来大大减少相同对象的初始化,减少内存开支,缺点是提高了系统复杂度,核心代码是必须要有一个工厂类来控制对象的创建。
END
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第九天,点击查看活动详情
PS:已经更文多少天,N就写几。一定要写对文案,否则文章不计入在内;模板句子需要带超链接。