设计模式-享元模式

1、概述

抽象享元(Flyweight):这是所有具体享元类的基类,它定义了享元对象的内部状态和外部状态,以及需要实现的公共接口。外部状态通常以参数的形式通过方法传入。
具体享元(Concrete Flyweight):这个角色实现了抽象享元中定义的接口,具体的享元类包含了实现细节,它们共享相同的内部状态,但可以根据需要存储或计算外部状态。
非享元(Unsharable Flyweight):代表不可以共享的外部状态,这些状态是特定于上下文的,因此不能共享。它们以参数的形式注入到具体享元的相关方法中。
享元工厂(Flyweight Factory):用于构建一个池容器,负责创建和管理享元对象。当客户端请求一个享元对象时,享元工厂会检查系统中是否已存在符合要求的享元对象,如果存在,则提供给客户;如果不存在,则创建一个新的享元对象

2、优缺点

优点

减少内存消耗:通过共享对象,可以显著减少系统中对象的数量,从而节省内存空间。这在处理大量相似对象时尤为有效,如数据库连接池、线程池等场景。
提高系统性能:由于减少了对象的创建和销毁,享元模式可以提高系统的响应速度和性能。在高并发场景下,如电商网站的购物车或在线游戏的排行榜,这种性能提升尤为显著。
支持对象共享:通过将对象的状态分为内部状态和外部状态,享元模式可以实现对象的可共享性。这使得多个对象可以共享相同的内部状态,而保持各自独立的外部状态。

缺点

实现较为复杂:享元模式需要将对象的状态分为内部状态和外部状态,这可能需要额外的设计和编程工作。同时,使用工厂类来管理共享对象也可能增加实现的复杂性。
可能影响系统维护性:将对象状态分为内部和外部状态可能会增加系统的复杂度,使得系统的维护和理解变得更加困难。此外,如果过度使用享元模式,可能会导致代码的可读性和可维护性下降。
可能降低代码可读性:由于享元模式使用工厂类来管理共享对象,可能会增加代码的抽象层次和间接性,从而降低代码的可读性。对于不熟悉该模式的开发人员来说,理解和维护代码可能会更加困难。

3、实现方式

import java.util.HashMap;
import java.util.Map;


//测试类
public class Test {
    public static void main(String[] args) {
        CoffeeFactory coffeeFactory = new CoffeeFactory();

        // 客户点咖啡
        Coffee coffee1 = coffeeFactory.getCoffeeFlavor("Cappuccino");
        coffee1.serve("Table 1");

        Coffee coffee2 = coffeeFactory.getCoffeeFlavor("Latte");
        coffee2.serve("Table 2");

        Coffee coffee3 = coffeeFactory.getCoffeeFlavor("Cappuccino");
        coffee3.serve("Table 3");

        // 输出享元工厂管理的咖啡种类数量
        System.out.println("Total Coffee flavors made: " + coffeeFactory.getTotalCoffeeFlavors());
    }
}

// 1. 享元接口
interface Coffee {
    void serve(String table);
}

// 2. 具体享元对象 - 具体的咖啡种类
class CoffeeFlavor implements Coffee {
    private final String flavor;

    public CoffeeFlavor(String flavor) {
        this.flavor = flavor;
    }

    @Override
    public void serve(String table) {
        System.out.println("Serving coffee flavor " + flavor + " to table " + table);
    }
}

// 3. 享元工厂
class CoffeeFactory {
    private final Map<String, Coffee> flavors = new HashMap<>();

    public Coffee getCoffeeFlavor(String flavor) {
        return flavors.computeIfAbsent(flavor, CoffeeFlavor::new);
    }

    public int getTotalCoffeeFlavors() {
        return flavors.size();
    }
}

4、应用场景

五子棋游戏:在五子棋游戏中,可以使用享元模式来表示棋子。由于棋盘上可能存在大量重复的棋子(例如黑棋或白棋),享元模式可以通过共享相同的棋子对象来减少内存占用。在这个场景中,棋子类可以作为抽象享元角色,而具体的颜色实例(如黑棋或白棋)则是具体享元角色。
文档编辑器:在文本编辑器或处理软件中,可以使用享元模式来管理文本中的字符。由于同一个文档中可能包含大量重复的字符,使用享元模式可以有效地减少内存消耗。在这种情况下,字符类是抽象享元角色,而具体的字符实例(如’a’、‘b’、’c’等)是具体享元角色。
网页开发:在网页开发中,可以使用享元模式来管理图标、图片或其他重复使用的图形元素。这有助于减少页面加载时间,并降低服务器的带宽需求。
网络游戏:在多人网络游戏中,可以使用享元模式来管理游戏中的角色、道具等资源。这有助于减少服务器的资源消耗,并提高游戏的可伸缩性。
电子商务平台:在电子商务平台中,可以使用享元模式来管理商品图片、评价等级图标等元素。这有助于减少页面加载时间,并提高用户体验。

This entry was posted in 应用, 设计模式. Bookmark the permalink.

发表评论