设计模式-享元模式(Flyweight)

设计模式-享元模式(Flyweight)

    • 一、享元模式概述
      • [1.1 什么是享元模式](#1.1 什么是享元模式)
      • [1.2 简单实现享元模式](#1.2 简单实现享元模式)
      • [1.3 使用享元模式的注意事项](#1.3 使用享元模式的注意事项)
    • 二、享元模式的用途
    • 三、享元模式实现方式
      • [3.1 单例享元模式(Singleton Flyweight)](#3.1 单例享元模式(Singleton Flyweight))
      • [3.2 工厂方法享元模式(Factory Method Flyweight)](#3.2 工厂方法享元模式(Factory Method Flyweight))
      • [3.3 抽象享元模式(Abstract Flyweight)](#3.3 抽象享元模式(Abstract Flyweight))
      • [3.4 组合享元模式(Composite Flyweight)](#3.4 组合享元模式(Composite Flyweight))
      • [3.5 装饰器享元模式(Decorator Flyweight)](#3.5 装饰器享元模式(Decorator Flyweight))

一、享元模式概述

1.1 什么是享元模式

享元模式,也称为Flyweight Pattern,是一种结构型设计模式,主要用于减少创建对象的数量以降低内存占用和提升性能。这种类型的设计模式尝试重用已有的同类对象,当没有找到匹配的对象时,才会创建新的对象。

享元模式的主要组成部分包括享元工厂、抽象享元和具体享元类。享元工厂负责创建和管理具体的享元对象,当请求对象已经存在时,直接返回该对象;当不存在时,就创建一个新的对象。抽象享元定义了需要共享的对象的业务接口,而具体享元则实现了抽象享元类的接口,完成了特定的业务逻辑。

在使用享元模式时,需要注意对内部状态和外部状态进行划分,并且需要一个工厂类来控制这个过程。通常,工厂方法会返回一个已缓存的实例,而不是创建一个新的实例,从而实现不可变实例的复用。

享元模式的经典应用场景是需要缓冲池的场景,例如String常量池和数据库连接池等。其主要目的是通过共享技术有效地支持大量细粒度的对象,如果有大量对象并且这些对象消耗大量内存时,采用享元模式可以显著提高性能。

1.2 简单实现享元模式

首先,我们定义一个抽象享元类(Flyweight):

java 复制代码
public abstract class Flyweight {
    private String name;

    public Flyweight(String name) {
        this.name = name;
    }

    public abstract void operation();
}

然后,我们定义具体享元类(ConcreteFlyweight),继承自抽象享元类:

java 复制代码
public class ConcreteFlyweight extends Flyweight {
    public ConcreteFlyweight(String name) {
        super(name);
    }

    @Override
    public void operation() {
        System.out.println("ConcreteFlyweight: " + name + " is using the shared resource.");
    }
}

接下来,我们定义享元工厂类(FlyweightFactory),用于创建和管理享元对象:

java 复制代码
import java.util.HashMap;
import java.util.Map;

public class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String name) {
        if (!flyweights.containsKey(name)) {
            flyweights.put(name, new ConcreteFlyweight(name));
        }
        return flyweights.get(name);
    }
}

最后,我们在客户端代码中使用享元工厂来创建和管理享元对象:

java 复制代码
public class Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight flyweight1 = factory.getFlyweight("A");
        Flyweight flyweight2 = factory.getFlyweight("B");
        Flyweight flyweight3 = factory.getFlyweight("A");

        flyweight1.operation();
        flyweight2.operation();
        flyweight3.operation();
    }
}

运行客户端代码,输出结果如下:

java 复制代码
ConcreteFlyweight: A is using the shared resource.
ConcreteFlyweight: B is using the shared resource.
ConcreteFlyweight: A is using the shared resource.

从输出结果可以看出,享元模式成功地实现了对相同对象的复用,避免了重复创建对象,提高了性能。

1.3 使用享元模式的注意事项

  • 1、合理划分内部状态和外部状态。享元对象应该将内部状态存储在对象内部,而外部状态可以通过参数传递或共享来处理。

  • 2、享元对象的创建和销毁应该由享元工厂负责。享元工厂需要维护一个享元池,当请求一个对象时,首先从池中查找是否已经存在该对象,如果存在则直接返回,否则创建新的对象并加入到池中。

  • 3、享元对象应该是不可变的。因为享元对象会被多线程共享,所以必须保证其不可变性,避免出现并发问题。

  • 4、享元模式适用于那些需要缓冲池的场景。例如String常量池、数据库连接池等。在这些场景下,通过共享技术可以有效地支持大量细粒度的对象,降低内存占用和提升性能。

  • 5、享元模式可能会增加系统的复杂性和维护成本。因为需要维护一个享元池,并且需要对享元对象进行管理和维护,所以会增加系统的复杂性和维护成本。因此,在使用享元模式时需要权衡利弊,根据具体情况进行选择。

二、享元模式的用途

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以降低内存占用和提升性能。这种类型的设计模式尝试重用已有的同类对象,当没有找到匹配的对象时,才会创建新的对象。

享元模式的典型应用场景是需要缓冲池的场景,例如String常量池和数据库连接池等。在这些场景下,通过共享技术可以有效地支持大量细粒度的对象,如果有大量对象并且这些对象消耗大量内存时,采用享元模式可以显著提高性能。

三、享元模式实现方式

3.1 单例享元模式(Singleton Flyweight)

单例享元模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点。在Java中,可以使用双重检查锁定(Double-Checked Locking)来实现单例享元模式。

以下是一个简单的Java实现单例享元模式的示例:

java 复制代码
public class SingletonFlyweight {
    private static volatile SingletonFlyweight instance;

    private SingletonFlyweight() {
        // 私有构造函数,防止外部实例化
    }

    public static SingletonFlyweight getInstance() {
        if (instance == null) {
            synchronized (SingletonFlyweight.class) {
                if (instance == null) {
                    instance = new SingletonFlyweight();
                }
            }
        }
        return instance;
    }
}

在这个示例中,我们使用了一个静态的volatile变量instance来存储单例对象。volatile关键字确保了多线程环境下对该变量的可见性。getInstance()方法首先检查instance是否为null,如果为null,则进入同步代码块。在同步代码块中,再次检查instance是否为null,如果仍然为null,则创建一个新的SingletonFlyweight对象并将其赋值给instance。这样,我们可以确保在整个应用程序中只有一个SingletonFlyweight实例。

3.2 工厂方法享元模式(Factory Method Flyweight)

工厂方法享元模式是一种创建型设计模式,它提供了一种在不指定具体类的情况下创建对象的方法。这种模式主要用于减少对象的创建次数,提高性能。

以下是一个简单的Java实现工厂方法享元模式的例子:

首先,我们定义一个接口Shape,所有的形状类都需要实现这个接口:

java 复制代码
public interface Shape {
    void draw();
}

然后,我们定义两个实现了Shape接口的具体类:Circle和Rectangle:

java 复制代码
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个矩形");
    }
}

接下来,我们定义一个工厂类ShapeFactory,它有一个静态方法getShape,根据传入的参数返回相应的形状对象:

java 复制代码
public class ShapeFactory {
    public static Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        if (shapeType.equalsIgnoreCase("CIRCLE")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
            return new Rectangle();
        }
        return null;
    }
}

最后,我们在主函数中测试一下这个工厂方法享元模式:

java 复制代码
public class FactoryPatternDemo {
    public static void main(String[] args) {
        Shape circle = ShapeFactory.getShape("CIRCLE");
        circle.draw();

        Shape rectangle = ShapeFactory.getShape("RECTANGLE");
        rectangle.draw();
    }
}

运行结果:

java 复制代码
画一个圆形
画一个矩形

3.3 抽象享元模式(Abstract Flyweight)

抽象享元模式是一种结构型设计模式,它提供了一种方式来管理和共享对象。在Java中,可以通过创建一个抽象类来实现抽象享元模式。以下是一个简单的示例:

首先,创建一个抽象的享元类,它将包含一个抽象方法getInstance(),用于获取享元对象的实例:

java 复制代码
public abstract class AbstractFlyweight {
    public abstract void operation();

    public static AbstractFlyweight getInstance(String key) {
        // 根据key获取对应的享元对象实例
        // 如果不存在,则创建一个新的实例并返回
        // 如果存在,则直接返回已有的实例
    }
}

接下来,为每种具体的享元对象实现一个子类。这些子类将继承抽象享元类,并实现其抽象方法operation():

java 复制代码
public class ConcreteFlyweightA extends AbstractFlyweight {
    @Override
    public void operation() {
        System.out.println("ConcreteFlyweightA operation");
    }
}

public class ConcreteFlyweightB extends AbstractFlyweight {
    @Override
    public void operation() {
        System.out.println("ConcreteFlyweightB operation");
    }
}

最后,在主程序中使用抽象享元类来获取和操作享元对象:

java 复制代码
public class Main {
    public static void main(String[] args) {
        AbstractFlyweight flyweightA = AbstractFlyweight.getInstance("A");
        flyweightA.operation();

        AbstractFlyweight flyweightB = AbstractFlyweight.getInstance("B");
        flyweightB.operation();
    }
}

运行上述代码,将输出以下结果:

java 复制代码
ConcreteFlyweightA operation
ConcreteFlyweightB operation

3.4 组合享元模式(Composite Flyweight)

组合享元模式是一种结构型设计模式,它通过将对象组合成树形结构来减少系统中对象的个数。在Java中,可以通过创建一个组合享元类来实现组合享元模式。以下是一个简单的示例:

首先,创建一个抽象组件类Component,它包含一个指向子组件的引用:

java 复制代码
public abstract class Component {
    protected String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public abstract void display();
}

然后,创建具体组件类Leaf和Composite,它们分别表示叶子节点和复合节点:

java 复制代码
public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }

    @Override
    public void display() {
        System.out.println("Leaf: " + getName());
    }
}

public class Composite extends Component {
    private List<Component> children = new ArrayList<>();

    public void add(Component component) {
        children.add(component);
    }

    public void remove(Component component) {
        children.remove(component);
    }

    @Override
    public void display() {
        System.out.println("Composite: " + getName());
        for (Component child : children) {
            child.display();
        }
    }
}

接下来,创建一个组合享元类CompositeFlyweight,它包含一个指向复合节点的引用:

java 复制代码
public class CompositeFlyweight extends Component {
    private Composite composite;

    public CompositeFlyweight(String name, Composite composite) {
        super(name);
        this.composite = composite;
    }

    @Override
    public void display() {
        composite.display();
    }
}

最后,在主程序中使用组合享元模式:

java 复制代码
public class Main {
    public static void main(String[] args) {
        Composite root = new Composite("root");
        Composite node1 = new Composite("node1");
        Composite node2 = new Composite("node2");
        Leaf leaf1 = new Leaf("leaf1");
        Leaf leaf2 = new Leaf("leaf2");
        Leaf leaf3 = new Leaf("leaf3");
        Leaf leaf4 = new Leaf("leaf4");

        root.add(node1);
        root.add(node2);
        node1.add(leaf1);
        node1.add(leaf2);
        node2.add(leaf3);
        node2.add(leaf4);

        CompositeFlyweight compositeFlyweight = new CompositeFlyweight("compositeFlyweight", root);
        compositeFlyweight.display();
    }
}

运行上述代码,将输出以下结果:

java 复制代码
Composite: compositeFlyweight
Composite: node1
Leaf: leaf1
Leaf: leaf2
Composite: node2
Leaf: leaf3
Leaf: leaf4

3.5 装饰器享元模式(Decorator Flyweight)

装饰器模式是一种结构型设计模式,它允许你在不修改原始类的情况下向对象添加新的功能。享元模式是一种优化技术,用于减少创建对象的数量,提高性能。

下面是一个使用Java实现的装饰器享元模式的例子:

首先,我们创建一个抽象组件类Component:

java 复制代码
public abstract class Component {
    public abstract void operation();
}

然后,我们创建一个具体组件类ConcreteComponent:

java 复制代码
public class ConcreteComponent extends Component {
    @Override
    public void operation() {
        System.out.println("执行具体组件的操作");
    }
}

接下来,我们创建一个抽象装饰器类Decorator,它也继承自Component类,并持有一个Component类型的引用:

java 复制代码
public abstract class Decorator extends Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        if (component != null) {
            component.operation();
        }
    }
}

现在,我们可以创建具体的装饰器类,例如ConcreteDecoratorA和ConcreteDecoratorB,它们分别在调用operation方法时添加额外的功能:

java 复制代码
public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        System.out.println("执行装饰器A的操作");
        super.operation();
    }
}

public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        System.out.println("执行装饰器B的操作");
        super.operation();
    }
}

最后,我们在客户端代码中使用这些装饰器来装饰ConcreteComponent对象:

java 复制代码
public class Client {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        Component decoratorA = new ConcreteDecoratorA(component);
        Component decoratorB = new ConcreteDecoratorB(decoratorA);

        decoratorB.operation();
    }
}

运行客户端代码,输出结果如下:

java 复制代码
执行装饰器B的操作
执行装饰器A的操作
执行具体组件的操作
相关推荐
大圣数据星球5 小时前
Fluss 写入数据湖实战
大数据·设计模式·flink
思忖小下6 小时前
梳理你的思路(从OOP到架构设计)_设计模式Template Method模式
设计模式·模板方法模式·eit
思忖小下16 小时前
梳理你的思路(从OOP到架构设计)_简介设计模式
设计模式·架构·eit
liyinuo201718 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范
aaasssdddd9620 小时前
C++的封装(十四):《设计模式》这本书
数据结构·c++·设计模式
T1an-120 小时前
设计模式之【观察者模式】
观察者模式·设计模式
思忖小下1 天前
梳理你的思路(从OOP到架构设计)_设计模式Factory Method模式
设计模式·工厂方法模式·eit
霁月风1 天前
设计模式——工厂方法模式
c++·设计模式·工厂方法模式
发飙的蜗牛'1 天前
23种设计模式
android·java·设计模式
NorthCastle1 天前
设计模式-创建型模式-简单工厂模式详解
设计模式·简单工厂模式