设计模式-享元模式(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的操作
执行具体组件的操作