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

一、享元模式概述

1.1 什么是享元模式

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

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

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

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

1.2 简单实现享元模式

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

public abstract class Flyweight {
    private String name;

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

    public abstract void operation();
}

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

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),用于创建和管理享元对象:

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);
    }
}

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

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();
    }
}

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

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实现单例享元模式的示例:

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,所有的形状类都需要实现这个接口:

public interface Shape {
    void draw();
}

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

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,根据传入的参数返回相应的形状对象:

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;
    }
}

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

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

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

运行结果:

画一个圆形
画一个矩形

3.3 抽象享元模式(Abstract Flyweight)

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

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

public abstract class AbstractFlyweight {
    public abstract void operation();

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

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

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");
    }
}

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

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

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

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

ConcreteFlyweightA operation
ConcreteFlyweightB operation

3.4 组合享元模式(Composite Flyweight)

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

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

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,它们分别表示叶子节点和复合节点:

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,它包含一个指向复合节点的引用:

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();
    }
}

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

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();
    }
}

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

Composite: compositeFlyweight
Composite: node1
Leaf: leaf1
Leaf: leaf2
Composite: node2
Leaf: leaf3
Leaf: leaf4

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

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

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

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

public abstract class Component {
    public abstract void operation();
}

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

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

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

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方法时添加额外的功能:

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对象:

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();
    }
}

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

执行装饰器B的操作
执行装饰器A的操作
执行具体组件的操作
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一碗油泼面

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值