设计模式之享元模式

享元模式

概述

享元模式(英语:Flyweight Pattern)是一种软件设计模式。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。

关于享元模式,一言以蔽之就是“通过尽量共享实例来避免new出新的实例”。

示例程序

大家肯定都有使用过淘宝、京东等一些购物软件,在商品详情中,几乎所有的数据都是不会发生变化的。用户在短期内访问该商品,变化的一般只有库存,如果我们new出新的实例,那每一个用户来访问,内存中都会多出一个新的实例,这时候我们应该将商品的大部分不变的信息作为共享实例。

UML类图

名字说明
Commodity不变的商品信息
Stock变化的商品库存信息
CommodityFactory商品工厂,用于生成Commodity
RedisUtils模拟redis中读取商品库存
CommodityController读取商品信息的接口

在这里插入图片描述

代码实现

Commodity

@Data
public class Commodity {
    private Integer id;//商品id
    private String name;//商品名称
    private BigDecimal price;//商品价格
    private Stock stock;//库存信息
}

Stock

@Data
@AllArgsConstructor
public class Stock {
    private Integer total;//商品总数
    private Integer used;//已用数量
}

CommodityFactory

public class CommodityFactory {
  	//核心思想在于将不需要变动的东西存入map中
    static Map<Integer, Commodity> commodityMap = new HashMap<>();

    public static Commodity getCommodity(Integer id){
        Commodity commodity = commodityMap.get(id);
        if (commodity == null){
            //实际业务中,图书信息因从数据库读取
            commodity = new Commodity();
            commodity.setId(id);
            commodity.setName("图解设计模式");
            commodity.setPrice(new BigDecimal(100));
            commodityMap.put(id,commodity);
        }
        return commodity;
    }
}

RedisUtils

RedisUtils模拟库存消耗

public class RedisUtils {
    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

    private AtomicInteger stock = new AtomicInteger(0);

    public RedisUtils() {
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            // 模拟库存消耗
            stock.addAndGet(1);
        }, 0, 100000, TimeUnit.MICROSECONDS);

    }

    public int getStockUsed() {
        return stock.get();
    }
}

CommodityController

@RestController
public class CommodityController {
    private RedisUtils redisUtils = new RedisUtils();

    public Commodity queryCommodityInfo(Integer id) {
        Commodity commodity = CommodityFactory.getCommodity(id);
        // 模拟从Redis中获取库存变化信息
        Stock stock = new Stock(1000, redisUtils.getStockUsed());
        commodity.setStock(stock);
        return commodity;
    }

}

test

@SpringBootTest
@Slf4j
class Practice1400ApplicationTests {
    @Autowired
    CommodityController commodityController;


    @Test
    void contextLoads() throws InterruptedException {
        for (int idx = 0; idx < 10; idx++) {
            int id = 10001;
            Commodity commodity = commodityController.queryCommodityInfo(id);
            log.info("测试结果:{} ", commodity);
            Thread.sleep(1200);
        }
    }

}

登场角色

  • Flyweight

    按照通常方式编写程序会导致程序变种,所以如果能够适应共享实例会比较好,而Flyweight角色就表示哪些实例会被共享的类。在示例程序中由Commodity扮演。

  • FlyweightFactory

    FlyweightFactory角色是生成Flyweight角色的工厂,在工厂中生成Flyweight角色可以实现共享实例。在示例程序中由CommodityFactory扮演该角色。

总结

享元模式的主题就是共享,那么在共享时应注意什么呢?

如果要改变被共享的对象,就会对多个地方产生影响

也就是说一个实例的改变会反映到所有使用该实例的地方,假设我们修改了商品名称,那么所有其他使用到商品名称的地方都会随之发生改变。

因此,在决定Flyweight角色时,需要精挑细选,只将哪些真正应该在多个地方共享的字段定义在Flyweight角色中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值