Java设计模式- 结构型设计模式-享元模式
从这一专栏开始将学习设计模式,上课学习和自己总结归纳的笔记将总结出来供大家参考。
参考书籍:《设计模式就该这样学》
其他文章:
文章目录
一、结构型设计模式
在GOF23种设计模式中,有三种类型的设计模式,分别是:创建型设计模式、结构型设计模式、行为型设计模式。
结构型设计模式有:代理模式、适配器模式、桥接模式、装饰模式、外观模式、享元模式、组合模式 7 种结构型模式。
类结构型模式:关心类的组合,由多个类组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
对象结构型模式:关心类与对象的组合,通过关联关系,在一个类中定义另外一个类的实例对象,然后通过该对象调用相应的方法。
二、享元模式
1.享元模式定义
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
2.内部状态和外部状态
享元模式提出了两个要求:细粒度和共享对象。这里就涉及到内部状态和外部状态,既将对象的信息分为两部分:内部状态和外部状态。
内部状态:指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变。
外部状态:指对象得以依赖的一个标记,是随环境改变而改变的,不可共享的状态。
3.享元模式的特点
优点:
相同对象只要保存一份,降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。
缺点:
为了使对象共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。需要分离出外部状态和内部状态,而且外部状态具有固有化性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。
适用环境:
1.系统中有大量相似对象。
2.这些对象消耗大量内存。
3.这些对象的状态大部分可以外部化。
4.这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。
5.系统不依赖于这些对象身份,这些对象是不可分辨的。
4.享元模式的角色
抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
非享元(Unsharalbe Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具有享元的相关方法中。
享元工厂(Flyweight Factory)角色 :负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检查系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在,则创建一个新的享元对象。
5.享元模式的类图
6.享元模式的代码实现
6.1具体案例:
该软件公司开发人员通过对围棋软件进行分析发现,在图中,围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。如果将每一个棋子都作为一个独立的对象存储在内存中,将导致该围棋软件在运行时所需内存空间较大,如何降低运行代价、提高系统性能是需要解决的一个问题。为了解决该问题,现使用享元模式来设计该围棋软件的棋子对象。
类图如下:
具体代码实现:
1.抽象享元类 :IgoChessman
/**
* 棋子抽象享元类
* @author WxrStart
* @create 2022-06-02 11:03
*/
public abstract class IgoChessman {
public abstract String getColor();
public void display(Coordinate coord) {
System.out.println("棋子颜色:" + this.getColor()+",棋子位置:"+coord.getX()+","+coord.getY());
}
}
2.具体享元类:BlackIgoChessman、WhiteIgoChessman
public class BlackIgoChessman extends IgoChessman {
public String getColor() {
return "黑色";
}
}
public class WhiteIgoChessman extends IgoChessman {
public String getColor() {
return "白色";
}
}
3.享元工厂类:IgoChessmanFactory
public class IgoChessmanFactory {
private static volatile IgoChessmanFactory igoChessmanFactory = null;
private static HashMap map;
private IgoChessmanFactory() {
map=new HashMap();
IgoChessman black,white;
black=new BlackIgoChessman();
white=new WhiteIgoChessman();
map.put("b",black);
map.put("w",white);
}
public static IgoChessmanFactory getInstance() {
if (igoChessmanFactory == null) {
synchronized (IgoChessmanFactory.class) {
if (igoChessmanFactory == null) {
igoChessmanFactory = new IgoChessmanFactory();
}
}
}
return igoChessmanFactory;
}
// 通过key获取存储在map中的享元对象
public static IgoChessman getIgoChessman(String color) {
return (IgoChessman) map.get(color);
}
}
4.非享元角色:Coordinate
/**
* 棋子坐标类
* @author WxrStart
* @create 2022-06-02 11:10
*/
public class Coordinate {
private int x,y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "Coordinate{" +
"x=" + x +
", y=" + y +
'}';
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
5.客户端测试类
public class Client {
public static void main(String[] args) {
IgoChessman black1, black2, black3, white1, white2;
IgoChessmanFactory factory;
// 获取享元工厂对象
factory = IgoChessmanFactory.getInstance();
// 通过享元工厂获取3颗黑子
black1 = factory.getIgoChessman("b");
black2 = factory.getIgoChessman("b");
black3 = factory.getIgoChessman("b");
System.out.println("判断两颗黑子是否相同:" + (black1 == black2));
// 通过享元工厂获取2颗白子
white1 = factory.getIgoChessman("w");
white2 = factory.getIgoChessman("w");
System.out.println("判断两颗白子是否相同:" + (white1 == white2));
// 显示棋子
black1.display(new Coordinate(1,2));
black2.display(new Coordinate(3,8));
black3.display(new Coordinate(4,7));
white1.display(new Coordinate(6,4));
white2.display(new Coordinate(3,2));
}
}