享元模式(Flyweight Pattern) - alvinlkk的个人空间

简介: 享元模式(Flyweight Pattern) - alvinlkk的个人空间

背景


面向对象可以非常方便的解决一些扩展性的问题,但是在这个过程中系统务必会产生一些类或者对象,如果系统中存在对象的个数过多时,将会导致系统的性能下降。对于这样的问题解决最简单直接的办法就是减少系统中对象的个数。

享元模式提供了一种解决方案,使用共享技术实现相同或者相似对象的重用。也就是说实现相同或者相似对象的代码共享。


定义


享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。 也就是运行共享技术有效地支持大量细粒度对象的复用。系统使用少量对象,而且这些都比较相似,状态变化小,可以实现对象的多次复用。

在了解享元模式之前我们先要了解两个概念:内部状态、外部状态。

  • 内部状态:在享元对象内部不随外界环境改变而改变的共享部分。
  • 外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。


模式结构


1671088878178.jpg

抽象享元角色:

public abstract class FlyWeight {
    //内部状态
    private String innerState;
    //外部状态
    private String outerState;
    public FlyWeight(String innerState) {
        this.innerState = innerState;
    }
    public abstract void operate();
    public String getOuterState() {
        return outerState;
    }
    public void setOuterState(String outerState) {
        this.outerState = outerState;
    }
}
复制代码

具体享元角色:

public class ConcreteFlyWeight1 extends FlyWeight {
    public ConcreteFlyWeight1(String innerState) {
        super(innerState);
    }
    @Override
    public void operate() {
        System.out.println("具体享元角色1");
    }
}
复制代码

享元工厂:

public class FlyWeightFactory {
    private static Map<String, FlyWeight> pool = new HashMap<String, FlyWeight>();
    public static FlyWeight getFlyweight(String innerState) {
        if(pool.get(innerState) != null) {
            return pool.get(innerState);
        } else {
            FlyWeight weight = new ConcreteFlyWeight1(innerState);
            pool.put(innerState, weight);
            return weight;
        }
    }
}
复制代码


模式实现


场景:围棋的棋子, 如果用编程去实现的话,势必要new出很多实例,整盘棋结束时估计内存也快爆了。如果使用享元模式,把围棋的共性共性出来,一些外部状态则外部动态控制,那么这个效率才是最优的。比如共享的应该是这个棋子的形状、大小、图片,外部动态修改的应该是棋子的位置。那么,只要定义两个类,黑棋和白棋,而且工厂中或说整个系统中也就只维护两个对象,一个是黑棋一个是白棋。

外部状态UnSharedConcreteFlyWeight非共享享元类:

public class Coordinate {
    private int x, y;
    public Coordinate(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 interface ChessFlyWeight {
    void setColor(String c);
    String getColor();
    void display(Coordinate coordinate);
}
复制代码

具体享元类:

public class ConcreteChess implements  ChessFlyWeight {
    private String color;
    public ConcreteChess(String color) {
        super();
        this.color = color;
    }
    @Override
    public void setColor(String c) {
    }
    @Override
    public String getColor() {
        return null;
    }
    @Override
    public void display(Coordinate c) {
        System.out.println("棋子颜色:"+color);
        System.out.println("棋子位置:"+c.getX()+"------"+c.getY());
    }
}
复制代码

工厂类:

public class ChessFlyWeightFactory {
    private static Map<String, ChessFlyWeight> map = new HashMap<String, ChessFlyWeight>();
    public static ChessFlyWeight getChess(String color) {
        if(map.get(color)!=null){
            return map.get(color);
        }else{
            ChessFlyWeight cfw = new ConcreteChess(color);
            map.put(color, cfw);
            return cfw;
        }
    }
}
复制代码

场景类:

public class Client {
    public static void main(String[] args) {
        ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("黑色");
        ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("黑色");
        System.out.println(chess1 == chess2);
        System.out.println("增加外部状态的处理============");
        chess1.display(new Coordinate(10,10));
        chess2.display(new Coordinate(20,20));
    }
}
复制代码


模式优缺点


优点

  • 享元模式的优点在于它能够极大的减少系统中对象的个数。 -享元模式由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。

缺点

  • 由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。
  • 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。


模式使用场景


  • 如果一个系统中存在大量的相同或者相似的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式来减少系统中对象的数量。
  • 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
  • 需要缓冲池的场景。


应用


  1. 在Java中,String类中用了享元模式。在JAVA中字符串常量都是存在常量池中的,JAVA会确保一个字符串常量在常量池中只有一个拷贝。String a="abc",其中"abc"就是一个字符串常量。
  2. 数据库连接池,线程池等即是用享元模式的应用。
目录
相关文章
|
7月前
|
设计模式 存储 安全
二十三种设计模式全面解析-享元模式(Flyweight Pattern)详解:构建高效共享的对象结构
二十三种设计模式全面解析-享元模式(Flyweight Pattern)详解:构建高效共享的对象结构
|
设计模式 存储 数据库
认真学习设计模式之享元模式(Flyweight Pattern)
认真学习设计模式之享元模式(Flyweight Pattern)
70 0
|
设计模式 Java 数据库连接
认真学习设计模式之委派模式(Delegate Pattern)
认真学习设计模式之委派模式(Delegate Pattern)
55 0
|
设计模式 Java 数据库
Java设计模式-享元模式(Flyweight Pattern)
Java设计模式-享元模式(Flyweight Pattern)
|
存储 缓存 Java
结构型模式 - 享元模式(Flyweight Pattern)
结构型模式 - 享元模式(Flyweight Pattern)
|
应用服务中间件 智能硬件 容器
结构型模式 - 外观模式(Facade Pattern)
结构型模式 - 外观模式(Facade Pattern)
建造者模式(Builder Pattern) - alvinlkk的个人空间
建造者模式(Builder Pattern) - alvinlkk的个人空间
99 0
建造者模式(Builder Pattern) - alvinlkk的个人空间
|
存储 设计模式 缓存
享元模式 Flyweight Pattern:减少对象数量
主要内容有: 该模式的介绍,包括: 引子、意图(大白话解释) 类图、时序图(理论规范) 该模式的代码示例:熟悉该模式的代码长什么样子 该模式的优缺点:模式不是万金油,不可以滥用模式 该模式的应用案例:了解它在哪些重要的源码中被使用
182 0
|
存储 设计模式 缓存
设计模式实战之享元模式(Flyweight Pattern)
设计模式实战之享元模式(Flyweight Pattern)
170 0
设计模式实战之享元模式(Flyweight Pattern)
|
设计模式 数据库连接
【愚公系列】2021年12月 二十三种设计模式(十一)-享元模式(Flyweight Pattern)
【愚公系列】2021年12月 二十三种设计模式(十一)-享元模式(Flyweight Pattern)
【愚公系列】2021年12月 二十三种设计模式(十一)-享元模式(Flyweight Pattern)