定义
享元模式(Flyweight Pattern)是一种结构型设计模式,它运用共享技术有效地支持大量细粒度的对象。享元模式的主要目的是减少系统中对象的数量,从而降低系统的内存占用和提高性能。
以下是享元模式的主要特点和定义:
一、主要角色
-
Flyweight(抽象享元角色) :
- 定义了享元对象的接口,规定了享元对象必须实现的方法。
-
ConcreteFlyweight(具体享元角色) :
- 实现了抽象享元角色所规定的接口,是可以共享的具体对象。
-
FlyweightFactory(享元工厂角色) :
- 负责创建和管理享元对象,确保合理地共享享元对象。当客户端请求一个享元对象时,享元工厂会检查是否已经存在符合要求的享元对象,如果存在则直接返回,否则创建一个新的享元对象并返回给客户端。
业务
假设我们正在开发一个游戏,游戏中有很多不同种类的树,每种树有不同的外观,但相同种类的树可以共享一些属性。
一、定义抽象享元角色和具体享元角色
- 首先定义树的抽象享元接口
Tree:
public interface Tree {
void draw(int x, int y);
}
- 然后实现具体享元角色,比如
OakTree(橡树)和PineTree(松树):
public class OakTree implements Tree {
private String texture; // 内部状态,假设是橡树的纹理图像路径
public OakTree() {
texture = "oak_texture.png";
}
@Override
public void draw(int x, int y) {
System.out.println("Drawing Oak Tree at (" + x + ", " + y + ") with texture: " + texture);
}
}
public class PineTree implements Tree {
private String texture; // 内部状态,假设是松树的纹理图像路径
public PineTree() {
texture = "pine_texture.png";
}
@Override
public void draw(int x, int y) {
System.out.println("Drawing Pine Tree at (" + x + ", " + y + ") with texture: " + texture);
}
}
二、创建享元工厂
import java.util.HashMap;
import java.util.Map;
public class TreeFactory {
private Map<String, Tree> trees = new HashMap<>();
public Tree getTree(String type) {
if (!trees.containsKey(type)) {
switch (type) {
case "oak":
trees.put(type, new OakTree());
break;
case "pine":
trees.put(type, new PineTree());
break;
}
}
return trees.get(type);
}
}
三、使用享元模式
public class Main {
public static void main(String[] args) {
TreeFactory factory = new TreeFactory();
Tree oakTree1 = factory.getTree("oak");
oakTree1.draw(10, 20);
Tree oakTree2 = factory.getTree("oak");
oakTree2.draw(30, 40);
Tree pineTree = factory.getTree("pine");
pineTree.draw(50, 60);
}
}
在这个例子中,Tree是抽象享元角色,OakTree和PineTree是具体享元角色,TreeFactory是享元工厂。通过享元工厂,相同种类的树(如橡树和松树)可以被共享,减少了内存占用,提高了性能。外部状态(树的位置)在使用时传入具体享元对象的方法中。
总结
一、使用场景
- 系统中存在大量相似的对象,这些对象消耗大量的内存资源。例如在一个文本编辑软件中,不同位置的相同字符可以作为享元对象共享,只需要存储一份字符的图像数据,而不是为每个字符都创建一个独立的对象。
- 对象的大部分状态可以外部化,即可以将对象的状态分为内部状态和外部状态,内部状态可以共享,外部状态由客户端传入或者在使用时动态确定。
二、优点
- 减少内存占用:通过共享对象,减少了系统中对象的数量,从而降低了内存占用。
- 提高性能:由于减少了对象的创建和销毁,提高了系统的性能。
三、缺点
- 增加了系统的复杂性:需要将对象的状态分为内部状态和外部状态,并且需要实现享元工厂来管理享元对象,增加了系统的设计和实现难度。
- 可能会影响对象的独立性:享元对象的共享可能会导致对象之间的耦合度增加,影响对象的独立性。