设计模式之享元模式

Posted ProChick

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之享元模式相关的知识,希望对你有一定的参考价值。

1.简要概述

  • 享元模式也叫作蝇量模式,就是以共享的方式高效的支持大量细粒度对象的重用,这些对象一部分内部状态是相同的。

  • 享元模式中的享元对象能做到共享的关键是区分了内部状态和外部状态,内部状态可以共享而且不会随环境变化而改变,外部状态不可以共享但会随环境变化而改变。

    💡举例:在围棋中,我们知道棋子的颜色分为黑色和白色,每个棋子所在棋盘的位置都不相同,所以这里棋子的颜色就可以看作是内部状态(可共享的),而棋子的位置就可以看作是外部状态(不可共享的)。

  • 享元模式能够解决重复对象的内存浪费问题,当系统中存有大量相似对象的时候,可以利用享元模式创建一个相关的缓冲池。如果需要该对象时,只需从缓冲池中获取即可,不必反复创建对象。

  • 享元模式最经典的应用场景就是池技术,比如:字符串常量池、数据库连接池等等。

2.模式结构

👉通常由一个享元工厂类( 负责创建并管理共享的享元对象,对外提供获取该对象的方法 ),一个享元抽象类或者接口( 负责声明公共方法,向外界提供对象的共享的内部状态,同时设置特有的外部状态 ),多个具体享元实现类( 负责实现具体的外部状态方法,并为内部状态提供成员变量进行存储 ),多个具体的非共享享元实现类( 定义不能够被共享的子类实现,不会出现在享元工厂 ),一个客户类( 负责通过享元工厂类获取指定的享元对象实例)共同组成。

3.实现代码

举例 💡 :假设我们现在要对围棋中的棋子通过对象进行表示,那么就可以使用享元模式来减少对象的重复创建,减少系统资源的利用。

棋子接口(享元抽象类)

public interface ChessFlyWeight {
	String getColor();
    
	void display(ChessLocation location);
}

棋子(具体享元实现类)

class Chess implements ChessFlyWeight{
    private String color;

    public Chess(String color) {
        this.color = color;
    }

    @Override
    public String getColor() {
        return color;
    }

    @Override
    public void display(ChessLocation location) {
        System.out.println("位置为:("+location.getX()+","+location.getY()+")");
    }
}

棋子位置(非共享享元实现类)

public class ChessLocation {
	private int x;
	private int y;
	
	public ChessLocation(int x, int y) {
		this.x = x;
		this.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;
	}
}

棋子工厂(享元工厂类)

public class ChessFactory {
    private static Map<String, Chess> chessMap = new HashMap<String, Chess>();

    public static ChessFlyWeight getChess(String color) {
        if (chessMap.containsKey(color))
        {
            return chessMap.get(color);
        } else {
            Chess chess = new Chess(color);
            chessMap.put(color, chess);
            
            return chess;
        }
    }
}

客户类

// 测试客户端
public class ChessClient{
    public static void main(String[] args) {
        ChessFlyWeight chess1 = ChessFactory.getChess("黑棋");
		ChessFlyWeight chess2 = ChessFactory.getChess("黑棋");
		
		System.out.println(chess1 == chess2); // true
		chess1.display(new ChessLocation(10, 10)); // 位置为(10,10)
        chess2.display(new ChessLocation(14, 15)); // 位置为(14,15)
		
        ChessFlyWeight chess3 = ChessFactory.getChess("白棋");
        
        System.out.println(chess1.getColor()); // 黑棋
        System.out.println(chess3.getColor()); // 白棋
    }
}

4.优点好处

  • 极大的减少了内存中对象的数量
  • 相同或相似的对象在内存中只存一份,极大的节约资源,提高了系统性能
  • 使用过程中,外部状态相对独立,不影响内部状态。

5.缺点弊端

  • 由于模式本身较为复杂,使程序逻辑复杂化,提高了系统的复杂度。
  • 为了节省内存,需要共享内部状态,分离外部状态,而读取外部状态使运行时间变长,所以用时间换取了空间。

6.应用场景

  • 当系统中存在很多完全相同或者相似对象的时候使用,用来节省内存。
  • 当系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分可以外部化的时候使用。

7.应用示例

JDK源码中的Integer类

从上面的代码中我们我可以看出,在Integer类的valueOf方法内部进行了一个判断,如果i的值在指定的范围区间,那就直接从缓存中取值,否则创建新的对象。所以这里就用到了享元模式,来提高系统的性能。

以上是关于设计模式之享元模式的主要内容,如果未能解决你的问题,请参考以下文章

学习设计模式之享元模式

设计模式之享元模式

JAVA设计模式之享元模式(flyweight)

JAVA设计模式之享元模式(flyweight)

设计模式之享元模式

设计模式之享元模式(结构型)