【设计模式系列13】今天才知道,原来我一直在用享元模式(2)

本文介绍了享元模式,一种用于减少内存消耗和提高性能的轻量级设计模式,通过对象池管理和复用细粒度对象。文章以火车票购买为例,展示了如何使用享元模式创建和管理对象池,以及如何根据内部状态和外部状态进行粒度划分。
摘要由CSDN通过智能技术生成

| 备忘录模式 | 登机入口 |

| 命令模式 | 登机入口 |

| 访问者模式 | 登机入口 |

| 软件设计7大原则和设计模式总结 | 登机入口 |

前言

===============================================================

我们知道,数据库的连接非常消耗性能,所以就有了连接池来减少连接操作的性能消耗;

如果一个系统中需要创建大量线程,也会消耗大量性能,所以就有了线程池。而我们在面向对象过程中,会创建大量对象,而如果有些对象可以被重复使用,那么我们是不是可以创建一个对象池来减少创建对象所带来的性能消耗呢?

答案是肯定的,这就是我们今天需要学习的享元模式做的事情。

什么是享元模式

====================================================================

享元模式(Flyweight Pattern),又称之为轻量级模式,是对象池的一种实现。主要用于减少创建对象的数量,以减少内存占用和提高性能。类似于我们的数据库连接池和线程池。

享元模式的宗旨就是共享细粒度对象,将多个对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,以此来降低内存的消耗。

享元模式属于结构型模式。

光讲理论不写代码的都是耍流氓,所以老规矩:Talk is cheap,Show you the code

享元模式示例

===================================================================

我们以买火车票为例子来进行示例。

1、首先创建一个车票的享元接口,定义一个查询车票信息方法:

package com.zwx.design.pattern.flyweight;

/**

  • 抽象享元角色

*/

public interface ITicket {

void info();

}

2、然后定义一个实现类来实现ITicket 接口:

package com.zwx.design.pattern.flyweight;

/**

  • 具体享元角色(粗粒度)

*/

public class TrainTicket implements ITicket{

private String from;

private String to;

public TrainTicket(String from, String to) {

this.from = from;

this.to = to;

}

@Override

public void info() {

System.out.println(from + “->” + to + “:硬座:100元,硬卧:200元”);

}

}

3、定义一个工厂类来管理享元对象:

package com.zwx.design.pattern.flyweight;

import java.util.HashMap;

import java.util.Map;

/**

  • 享元对象工厂

*/

public class TicketFactory {

private static Map<String,ITicket> CACHE_POOL = new HashMap<>();

public static ITicket getTicketInfo(String from,String to){

String key = from + “->” + to;

if (TicketFactory.CACHE_POOL.containsKey(key)){

System.out.println(“使用缓存”);

return TicketFactory.CACHE_POOL.get(key);

}

System.out.println(“未使用缓存”);

ITicket ticket = new TrainTicket(from,to);

CACHE_POOL.put(key,ticket);

return ticket;

}

}

工厂类主要使用了一个Map来存储对象,把火车票的出发地和目的地作为key值,如果存在了则直接从Map取,否则就新创建一个对象,并且加入到Map中。

4、最后写一个测试类来测试一下:

package com.zwx.design.pattern.flyweight;

public class TestTicket {

public static void main(String[] args) {

ITicket ticket = TicketFactory.getTicketInfo(“深圳”,“广州”);

ticket.info();//首次创建对象

ticket = TicketFactory.getTicketInfo(“深圳”,“广州”);

ticket.info();//使用缓存

ticket = TicketFactory.getTicketInfo(“深圳”,“北京”);

ticket.info();//换了目的地,无法使用缓存

}

}

输出结果为:

未使用缓存

深圳->广州:硬座:100元,硬卧:200元

使用缓存

深圳->广州:硬座:100元,硬卧:200元

未使用缓存

深圳->广州:硬座:100元,硬卧:200元

可以看到,深圳->广州的车票,第二次查询时使用了缓存。

看到这个写法,可能有人要有疑问了,这不就是容器式单例模式的写法吗?是的,这其实就是一种容器式单例模式的写法,但是它和单例模式的关注点不一样,单例模式关注的是整个类只能存在一个实例,而享元模式关注的是实例对象,对于可以共享状态的实例对象实现缓存(唯一)。

上面的写法也有一个缺陷,比如车票价钱是写死的,假如我们只想查硬座,或者只想查硬卧呢,这又该如何实现呢?这就要涉及到享元模式的粒度划分了

享元模式状态

===================================================================

上面的例子中,我们可以把实例对象划分一下,比如上面车票的对象,我们可以把from和to两个属性作为可共享状态,不可改变。然后再新增一个属性用来对应座位。这就是享元模式的内部状态外部状态

内部状态


内部状态指对象共享出来的信息,存储在享元对象内部并且不会随环境的改变而改变

外部状态


外部状态指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。

请看下面示例2就是根据内部状态和外部状态改写之后的例子:

享元模式示例2

====================================================================

1、首先创建一个车票的享元接口,定义一个查询车票信息方法和一个设置座位的方法:

package com.zwx.design.pattern.flyweight;

/**

  • 抽象享元角色

*/

public interface IShareTicket {

void info();

void setSeat(String seatType);

}

2、然后定义一个实现类来实现IShareTicket 接口(当然,这里的价钱还是写死的,示例主要是用来体会设计模式的思想):

package com.zwx.design.pattern.flyweight;

import java.math.BigDecimal;

/**

  • 具体享元角色(细粒度)

*/

public class TrainShareTicket implements IShareTicket {

private String from;//内部状态

private String to;//内部状态

private String seatType = “站票”;//外部状态

public TrainShareTicket(String from, String to) {

this.from = from;

this.to = to;

}

@Override

public void setSeat(String seatType){

this.seatType = seatType;

}

@Override

public void info() {

System.out.println(from + “->” + to + “:” + seatType + this.getPrice(seatType));

}

private BigDecimal getPrice(String seatType){

BigDecimal value = null;

switch (seatType){

case “硬座”:

value = new BigDecimal(“100”);

break;

case “硬卧”:

value = new BigDecimal(“200”);

break;

default:

value = new BigDecimal(“50”);

}

return value;

}

}

这个相比较于上面的示例,多了一个seatType属性,也多了一个设置座位的对外方法。

3、定义一个工厂类来管理享元对象:

package com.zwx.design.pattern.flyweight;

import java.util.HashMap;

import java.util.Map;

/**

  • 享元对象工厂

*/

public class TicketShareFactory {

private static Map<String,IShareTicket> CACHE_POOL = new HashMap<>();

public static IShareTicket getTicketInfo(String from,String to){

String key = from + “->” + to;

if (TicketShareFactory.CACHE_POOL.containsKey(key)){

System.out.println(“使用缓存”);

return TicketShareFactory.CACHE_POOL.get(key);

}

System.out.println(“未使用缓存”);

IShareTicket ticket = new TrainShareTicket(from,to);

CACHE_POOL.put(key,ticket);

return ticket;

}

}

4、最后写一个测试类来测试一下:

package com.zwx.design.pattern.flyweight;

public class TestShareTicket {

public static void main(String[] args) {

IShareTicket ticket = TicketShareFactory.getTicketInfo(“深圳”,“广州”);

ticket.setSeat(“硬座”);

ticket.info();//首次创建对象

ticket = TicketShareFactory.getTicketInfo(“深圳”,“广州”);

ticket.setSeat(“硬卧”);

ticket.info();//外部状态改变了,但是内部状态共享,依然可以使用缓存

}

}

输出结果:

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。

麻烦帮忙转发一下这篇文章+关注我

就这一次!拼多多内部架构师培训Kafka源码笔记(现已绝版)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

大型分布式系统犹如一个生命,系统中各个服务犹如骨骼,其中的数据犹如血液,而Kafka犹如经络,串联整个系统。这份Kafka源码笔记通过大量的设计图展示、代码分析、示例分享,把Kafka的实现脉络展示在读者面前,帮助读者更好地研读Kafka代码。

麻烦帮忙转发一下这篇文章+关注我

[外链图片转存中…(img-p1CfURkD-1713554269658)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值