首页 > 编程语言 >设计模式-享元模式在Java中的使用示例-围棋软件

设计模式-享元模式在Java中的使用示例-围棋软件

时间:2023-07-19 14:44:57浏览次数:35  
标签:享元 状态 享元池 示例 对象 设计模式 public 享元类

场景

享元模式

简介

当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。

例如在一个文本字符串中存在很多重复的字符,如果每一个字符都用一个单独的对象来表示,将会占用

较多的内存空间,那么我们如何去避免系统中出现大量相同或相似的对象,同时又不影响客户端程序。

通过面向对象的方式对这些对象进行操作?

享元模式正为解决这一类问题而诞生。享元模式通过共享技术实现相同或相似对象的重用,

在逻辑上每一个出现的字符都有一个对象与之对应,然而在物理上它们却共享同一个享元对象,

这个对象可以出现在一个字符串的不同地方,相同的字符对象都指向同一个实例,在享元模式中,

存储这些共享实例对象的地方称为享元池(Flyweight Pool)。我们可以针对每一个不同的字符创建一个享元对象,

将其放在享元池中,需要时再从享元池取出。

享元模式以共享的方式高效地支持大量细粒度对象的重用,享元对象能做到共享的关键是区分了内部

状态(Intrinsic State)和外部状态(Extrinsic State)。

下面将对享元的内部状态和外部状态进行简单的介绍:

(1) 内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享。如字符的内容,

不会随外部环境的变化而变化,无论在任何环境下字符“a”始终是“a”,都不会变成“b”。

(2) 外部状态是随环境改变而改变的、不可以共享的状态。享元对象的外部状态通常由客户端保存,

并在享元对象被创建之后,需要使用的时候再传入到享元对象内部。一个外部状态与另一个外部状态

之间是相互独立的。如字符的颜色,可以在不同的地方有不同的颜色,例如有的“a”是红色的,

有的“a”是绿色的,字符的大小也是如此,有的“a”是五号字,有的“a”是四号字。而且字符的颜色和大

小是两个独立的外部状态,它们可以独立变化,相互之间没有影响,客户端可以在使用时将外部状态

注入享元对象中。

正因为区分了内部状态和外部状态,我们可以将具有相同内部状态的对象存储在享元池中,享元池中

的对象是可以实现共享的,需要的时候就将对象从享元池中取出,实现对象的复用。通过向取出的对

象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份。

享元模式结构图

 

享元模式角色

Flyweight(抽象享元类):

通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),

同时也可以通过这些方法来设置外部数据(外部状态)。

ConcreteFlyweight(具体享元类):

它实现了抽象享元类,其实例称为享元对象;在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,

为每一个具体享元类提供唯一的享元对象。

UnsharedConcreteFlyweight(非共享具体享元类):

并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;

当需要一个非共享具体享元类的对象时可以直接通过实例化创建。

FlyweightFactory(享元工厂类):

享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,

享元池一般设计为一个存储“键值对”的集合(也可以是其他类型的集合),可以结合工厂模式进行设计;

当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已创建的实例或者创建一个新的实例(如果不存在的话),

返回新创建的实例并将其存储在享元池中。

在享元模式中引入了享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,当用户需要对象时,

首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

应用实例

通过对围棋软件进行分析,发现在围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。

如果将每一个棋子都作为一个独立的对象存储在内存中,将导致该围棋软件在运行时所需内存空间较大,

如何降低运行代价、提高系统性能是一个问题。为了解决这个问题,决定使用享元模式来设计该围棋软件的棋子对象。

IgoChessman充当抽象享元类,BlackIgoChessman和WhiteIgoChessman充当具体享元类,IgoChessmanFactory充当享元工厂类。

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi

实现

1、新建围棋棋子类作为抽象享元类

//围棋棋子类:抽象享元类
abstract class IgoChessman {
    public abstract String getColor();
    public void display(Coordinates coordinates){
        System.out.println("棋子颜色:"+this.getColor()+",棋子位置:"+coordinates.getX()+coordinates.getY());
    }
}

这里棋子的位置作为外部状态。

附坐标位置类

//坐标类:外部状态类
public class Coordinates {
    private int x;
    private int y;

    public Coordinates(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;
    }
}

2、新建黑色棋子类作为具体享元类

//黑色旗子类:具体享元类
public class BlackIgoChessman extends IgoChessman{

    @Override
    public String getColor() {
        return "黑色";
    }
}

3、新建白色棋子类作为具体享元类

//白色旗子类:具体享元类
public class WhiteIgoChessman extends IgoChessman{

    @Override
    public String getColor() {
        return "白色";
    }
}

4、新建围棋棋子工厂类作为享元工厂类,使用单例模式进行设计

//围棋棋子工厂类:享元工厂类,使用单例模式进行设计
public class IgoChessmanFactory {
    private static IgoChessmanFactory instance = new IgoChessmanFactory();
    //使用Hashtable来存储享元对象,充当享元池
    private static Hashtable ht;

    private IgoChessmanFactory(){
        ht = new Hashtable();
        IgoChessman black,white;
        black = new BlackIgoChessman();
        ht.put("b",black);
        white = new WhiteIgoChessman();
        ht.put("w",white);
    }

    //返回享元工程类的唯一实例
    public static IgoChessmanFactory getInstance(){
        return instance;
    }

    //通过key来获取存储在Hashtable中的享元对象
    public static IgoChessman getIgoChessman(String color){
        return (IgoChessman) ht.get(color);
    }
}

5、客户端调用示例

public class Client {
    public static void main(String[] args) {
        IgoChessman black1,black2,black3,white1,white2;
        IgoChessmanFactory factory;

        //获取享元工厂对象
        factory = IgoChessmanFactory.getInstance();
        //通过享元工厂获取三颗黑子
        black1 = factory.getIgoChessman("b");
        black2 = factory.getIgoChessman("b");
        black3 = factory.getIgoChessman("b");
        System.out.println("判断两颗黑子是否相同:"+(black1 == black2));
        //通过享元工厂获取两颗白子
        white1 = factory.getIgoChessman("w");
        white2 = factory.getIgoChessman("w");
        System.out.println("判断两颗白子是否相同:"+(white1 == white2));
        //显示棋子
        black1.display(new Coordinates(1,1));
        black2.display(new Coordinates(2,1));
        black3.display(new Coordinates(3,2));
        white1.display(new Coordinates(4,3));
        white2.display(new Coordinates(5,2));
    }
}

6、总结

当系统中存在大量相同或者相似的对象时,享元模式是一种较好的解决方案,它通过共享技术实现相

同或相似的细粒度对象的复用,从而节约了内存空间,提高了系统性能。相比其他结构型设计模式,

享元模式的使用频率并不算太高,但是作为一种以“节约内存,提高性能”为出发点的设计模式,它在

软件开发中还是得到了一定程度的应用。

享元模式的主要优点如下:

(1) 可以极大减少内存中对象的数量,使得相同或相似对象在内存中只保存一份,从而可以节约系统资源,提高系统性能。

(2) 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

主要缺点

(1) 享元模式使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。

(2) 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。

适用场景

(1) 一个系统有大量相同或者相似的对象,造成内存的大量耗费。

(2) 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。

(3) 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,

因此,应当在需要多次重复使用享元对象时才值得使用享元模式。

标签:享元,状态,享元池,示例,对象,设计模式,public,享元类
From: https://www.cnblogs.com/badaoliumangqizhi/p/17565505.html

相关文章

  • Go语言Revel框架 的聊天室示例解读
    安装Revel框架请参看下面这篇文章:《Go语言Revel框架准备工作》 运行聊天室例子运行聊天室例子只需执行下面命令:$revelrungithub.com/robfig/revel/samples/chat$revelrungithub.com/robfig/revel/samples/chat~~revel!http://robfig.github.com/revel~2013/03/2511:54:4......
  • 设计模式-外观模式在Java中的使用示例
    场景外观模式外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。示例自己泡茶和去茶馆喝茶的区别,如果是自己泡茶需要自行准备茶叶、......
  • Android平台GB28181设备接入侧音频采集推送示例
    技术背景GB/T28181是广泛应用于视频监控行业的标准协议规范,可以在不同设备之间实现互联互通。今天我们主要探讨Android平台的Audio采集部分。先说如何拿到数据源,在Android平台上采集音频,常用的方式如下:使用MediaRecorder类:MediaRecorder类提供了一组API,可以用于录制音频。您可以使......
  • AIGC 之 Stable Diffusion 生成的带文字图片示例
    文字文字为HOTAIGC网址导航效果图片1图片2图片3图片4图片5图片6图片7图片8大家觉得效果如何,要是大家感兴趣下篇分享生成原理及参数。......
  • php实现站群软件权限管理功能示例
    1.管理员页面RBAC.php<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>权限管理</title><scriptsrc="bootstrap/js/jquery-1.11.2.min.js"></script></head><body>......
  • 设计模式-组合模式在Java中的使用示例-杀毒软件针对文件和文件夹进行杀毒
    场景组合模式组合模式(CompositePattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。在组合模式中引......
  • python 使用OpenCV进行目标检测和识别的完整示例
    #导入OpenCV库importcv2#加载图像image=cv2.imread('image.jpg')#创建Haar级联分类器cascade_classifier=cv2.CascadeClassifier('haarcascade_frontalface_default.xml')#检测目标图像中的行人gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)faces=ca......
  • 享元模式
    目录1.概述2.结构3.案例实现4.优缺点和使用场景5.JDK源码解析1.概述定义:​ 运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象的开销,从而提高系统资源的利用率。2.结构享元(Flyweight)模式中......
  • beginnersbook C 语言示例·翻译完成 | ApacheCN
    译者:飞龙协议:CCBY-NC-SA4.0简单的C程序C语言中的HelloWorld程序C程序:检查给定的整数是正还是负C程序:使用递归函数反转给定的数字C程序:查找最大的三个数字C程序:显示Fibonacci序列C程序:使用递归查找数字的阶乘C程序:查找给定范围内的素数C程序:检查阿姆斯特朗数C程序......
  • Spring框架中的设计模式(重点学习!!!)
    Spring中的设计模式Spring框架中用到的设计模式有很多,以下是一些常见的设计模式:依赖注入(DI)和控制反转(IoC):这是Spring框架最核心的设计模式,它允许开发人员将对象之间的依赖关系从代码中抽离出来,由Spring容器负责管理和注入对象之间的依赖关系。工厂模式:Spring框架中的BeanFactor......