C++ 设计模式之享元模式

news2024/11/15 9:12:21

【声明】本题目来源于卡码网(题目页面 (kamacoder.com))

【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】


【简介】什么是享元模式 -- 可重复使用

        享元模式是⼀种结构型设计模式,在享元模式中,对象被设计为可共享的,可以被多个上下⽂使⽤,⽽不必在每个上下⽂中都创建新的对象。
        想要了解享元模式,就必须要区分什么是内部状态,什么是外部状态。

  • 内部状态是指那些可以被多个对象共享的状态,它存储在享元对象内部,并且对于所有享元对象都是相同的,这部分状态通常是不变的
  • 外部状态是享元对象依赖的、可能变化的部分。这部分状态不存储在享元对象内部,⽽是在使⽤享元对象时通过参数传递给对象。

        举个例⼦,图书馆中有很多相同的书籍,但每本书都可以被多个⼈借阅,图书馆⾥的书就是内部状态,⼈就是外部状态。
        再举个开发中的例⼦,假设我们在构建⼀个简单的图形编辑器,⽤户可以在画布上绘制不同类型的图形,⽽图形就是所有图形对象的内部状态(不变的),⽽图形的坐标位置就是图形对象的外部状态(变化的)。
        如果图形编辑器中有成千上万的图形对象,每个图形对象都独⽴创建并存储其内部状态,那么系统的内存占⽤可能会很⼤,在这种情况下,享元模式共享相同类型的图形对象,每种类型的图形对象只需创建⼀个共享实例,然后通过设置不同的坐标位置个性化每个对象,通过共享相同的内部状态,降低了对象的创建和内存占⽤成本。


【基本结构】

        享元模式包括以下⼏个重要⻆⾊:

  • 享元接⼝Flyweight : 所有具体享元类的共享接⼝,通常包含对外部状态的操作。
  • 具体享元类ConcreteFlyweight : 继承Flyweight 类或实现享元接⼝,包含内部状态。
  • 享元⼯⼚类FlyweightFactory : 创建并管理享元对象,当⽤户请求时,提供已创建的实例或者创建⼀个。
  • 客户端Client : 维护外部状态,在使⽤享元对象时,将外部状态传递给享元对象。


【简易实现】

         享元模式的实现通常涉及以下步骤:(以Java代码作以说明)

1. 定义享元接⼝,接受外部状态作为参数并进⾏处理。

// 步骤 1: 定义享元接⼝
interface Flyweight {
    // 操作外部状态
    void operation(String externalState);
}

2. 实现具体享元类, 存储内部状态。

// 步骤 2: 实现具体享元类
class ConcreteFlyweight implements Flyweight {
    private String intrinsicState; // 内部状态

    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }

    @Override
    public void operation(String externalState) {
        System.out.println("Intrinsic State: " + intrinsicState + ", External State: "
        + externalState);
    }
}

3. 创建享元⼯⼚类,创建并管理Flyweight 对象,当⽤户请求⼀个Flyweight 时,享元⼯⼚会提供⼀个已经创建的实例或者创建⼀个。

class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteFlyweight(key));
        }
        return flyweights.get(key);
    }
}

4. 客户端使⽤享元模式

public class Main {
    public static void main(String[] args) {
    FlyweightFactory factory = new FlyweightFactory();

    // 获取或创建享元对象,并传递外部状态
    Flyweight flyweight1 = factory.getFlyweight("A");
    flyweight1.operation("External State 1");

    Flyweight flyweight2 = factory.getFlyweight("B");
    flyweight2.operation("External State 2");

    Flyweight flyweight3 = factory.getFlyweight("A"); // 【重复使⽤!】已存在的享元对象
    flyweight3.operation("External State 3");
    }
}

【使用场景】

        使⽤享元模式的关键在于包含⼤量相似对象,并且这些对象的内部状态可以共享。具体的应⽤场景包括⽂本编辑器,图形编辑器,游戏中的⻆⾊创建,这些对象的内部状态⽐较固定(外观,技能,形状),但是外部状态变化⽐较⼤时,可以使⽤。


【编码部分】

1. 题目描述

        在一个图形编辑器中,用户可以绘制不同类型的图形,包括圆形(CIRCLE)、矩形(RECTANGLE)、三角形(TRIANGLE)等。现在,请你实现一个图形绘制程序,要求能够共享相同类型的图形对象,以减少内存占用;

2. 输入描述

       输入包含多行,每行表示一个绘制命令。每个命令包括两部分: 图形类型(Circle、Rectangle 或 Triangle) 绘制的坐标位置(两个整数,分别表示 x 和 y);

3. 输出描述

        对于每个绘制命令,输出相应图形被绘制的位置信息。如果图形是首次绘制,输出 "drawn at",否则输出 "shared at"。

4. C++ 编码部分

/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file FlyWeightMode.hpp
* @brief 享元模式
* @autor 写代码的小恐龙er
* @date 2024/01/13
*/

#include <iostream>
#include <string>
#include <vector>
#include <map>

using namespace std;

// 形状枚举类
enum class ShapeType{
    CIRCLE,   // 圆形
    RECTANGLE,// 矩形
    TRIANGLE, // 三角形
};

// 前置声明

// 图形位置
class Position;
// 1 -- 享元接口类
class Shape;
// 2 -- 具体实现享元接口
class ConcreteShape;
// 3 -- 享元工厂
class ShapeFactory;

// 图形位置
class Position
{
// 成员数据
private:
    int _x;
    int _y;
    
// 成员函数
public:
    Position(){}
    Position(int x, int y){
        this->_x = x;
        this->_y = y;
    }
    
    // 成员函数获取接口
    int GetX(){
        return _x;
    }
    int GetY(){
        return _y;
    }
};

// 1 -- 享元接口类
class Shape
{
// 接口函数
public:
    virtual void DrawShape(Position *position) = 0;
};

// 2 -- 具体实现享元接口
class ConcreteShape : public Shape
{
// 成员数据
private:
    // 形状类型
    ShapeType _shapeType;
    // 首次绘制标志
    bool _firstTime = true;
// 成员函数
public:
    // 通过 形状类型来创建具体的对象
    ConcreteShape(ShapeType shapeType){
        this->_shapeType = shapeType;
    }
    // 设置是否首次绘制标志位
    void SetFirstTime(bool flag){
        this->_firstTime = flag;
    }
    // 重载基类的接口函数
    void DrawShape(Position *position){
        string outStr = "";
        
        switch(_shapeType)
        {
        case ShapeType::CIRCLE:
            outStr = "CIRCLE";
            break;
        case ShapeType::RECTANGLE:
            outStr = "RECTANGLE";
            break;
        case ShapeType::TRIANGLE:
            outStr = "TRIANGLE";
            break;
        }

        if(_firstTime) outStr += " drawn at (";
        else outStr += " shared at (";
        
        std::cout << outStr << (position->GetX()) << ", " << (position->GetY()) << ")" << endl;
    }
};

// 3 -- 享元工厂
class ShapeFactory
{
// 成员数据
private:
    // 包含可扩展的享元类
    std::map<ShapeType, Shape*> _shapesMap;
    
// 成员函数
public:
    Shape* GetShape(ShapeType type){
        std::map<ShapeType, Shape*>::iterator pos = _shapesMap.find(type);
        if(pos == _shapesMap.end())
        {
            // 如果在map中找不到具体的形状实现类 则新建
            _shapesMap.insert(make_pair(type, new ConcreteShape(type)));
        }
        
        // 返回 具体的形状实现类
        return _shapesMap[type];
    }
};

int main()
{
    // 形状类型 
    string type;
    // x y
    int x = 0;
    int y = 0;
    // 新建位置类
    Position *position = nullptr;
    
    // 新建享元工厂类
    ShapeFactory *shapeFactory = new ShapeFactory();
    
    while(std::cin >> type >> x >> y)
    {
        // 形状类型
        ShapeType shapeType;
        if(type == "CIRCLE")
        {
            shapeType = static_cast<ShapeType>(0);
        }
        else if(type == "RECTANGLE")
        {
            shapeType = static_cast<ShapeType>(1);
        }
        else if(type == "TRIANGLE")
        {
            shapeType = static_cast<ShapeType>(2);
        }
        
        // 位置类
        position = new Position(x, y);
        
        // 具体的享元实现类
        Shape *shape = shapeFactory->GetShape(shapeType);
        
        // 先进行绘制操作
        shape->DrawShape(position);
        
        // 通过 dynamic_cast 向下类型转换
        ConcreteShape *concreteShape = dynamic_cast<ConcreteShape *> (shape);
        if(concreteShape == nullptr) return 0;
        
        // 再将该类型的标志位置为false
        concreteShape->SetFirstTime(false);
    }
    
    
    // 析构
    if(position != nullptr){
        delete position;
        position = nullptr;
    }

    delete shapeFactory;
    shapeFactory = nullptr;
    
    return 0;
}



......

To be continued.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1387781.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于深度学习的桃子熟度与大小智能检测

基于深度学习的桃子熟度与大小智能检测 基于深度学习的桃子熟度与大小智能检测引言1. 环境搭建与准备2. 数据准备3. 模型准备4. 训练准备5. 服务器端部署结语 基于深度学习的桃子熟度与大小智能检测 引言 随着时代的快速发展&#xff0c;人工智能时代为中国农业带来了新的机遇…

Leetcode刷题【每日n题】(1)

目录 1.题目一 2.思路分析 3.代码实现 4.题目二 5.思路分析 6.代码实现 1.题目一 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴…

Vue-20、Vue.set()的使用

1、添加对象某个属性 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Vue.set()的使用</title><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/vue2/dist…

2023.12.30性质

若连通图上各边的权值均不相同&#xff0c;则该图的最小生成树是唯一的。 由k算法&#xff0c;即由边从小到大的顺序构造&#xff0c;如果边权值各不相同&#xff0c;那么构造出来的最小生成树唯一&#xff0c;就是唯一的顺序&#xff0c;从小到大 关于带权无向图的最小生成…

动态pv(nfs方式挂载)

1、定义 发布pvc之后可以生成pv&#xff0c;还可以在共享服务器上直接生成挂载目录 pvc直接绑定和使用pv 2、动态pv依赖两个组件 &#xff08;1&#xff09;provisioner卷插件&#xff1a;k8s本身支持的动态pv创建不包括nfs&#xff0c;需要声明和安装一个外部插件provisio…

HDFS和MapReduce综合实训

文章目录 第1关&#xff1a;WordCount词频统计第2关&#xff1a;HDFS文件读写第3关&#xff1a;倒排索引第4关&#xff1a; 网页排序——PageRank算法 第1关&#xff1a;WordCount词频统计 测试说明 以下是测试样例&#xff1a; 测试输入样例数据集&#xff1a;文本文档test1…

canvas截取视频图像(图文示例)

查看专栏目录 canvas示例教程100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

[VGG团队论文阅读]Free3D: Consistent Novel View Synthesis without 3D Representation

Vedaldi, C. Z. A. (n.d.). Free3D: Consistent Novel View Synthesis without 3D Representation. Chuanxiaz.com. https://chuanxiaz.com/free3d/static/videos/Free3D.pdf Free3D: 无需3D表示的一致新视角合成 Visual Geometry Group, University of Oxford 摘要 我们介绍…

C# 面向切面编程之AspectCore初探

写在前面 AspectCore 是Lemon名下的一个国产Aop框架&#xff0c;提供了一个全新的轻量级和模块化的Aop解决方案。面向切面也可以叫做代码拦截&#xff0c;分为静态和动态两种模式&#xff0c;AspectCore 可以实现动态代理&#xff0c;支持程序运行时在内存中“临时”生成 AOP 动…

Mindspore 公开课 - prompt

prompt 介绍 Fine-Tuning to Prompt Learning Pre-train, Fine-tune BERT bidirectional transformer&#xff0c;词语和句子级别的特征抽取&#xff0c;注重文本理解Pre-train: Maked Language Model Next Sentence PredictionFine-tune: 根据任务选取对应的representatio…

Android 仿快手视频列表,RecyclerView与Banner联动效果

这是看到群里讨论过快手APP的一个观看他人视频列表的一个联动效果&#xff0c;但是并不是完全按照这个软件的效果来做的&#xff0c;只是参考&#xff0c;并不是完全仿照这个软件来做的&#xff0c;没时间去优化排版问题了&#xff0c;请见谅&#xff0c;如图&#xff1a; 实现…

pycharm管理仓库(Manager Repository)不见了

经常使用pycharm的大佬们都知道&#xff0c;pycharm中内置了很多库和包&#xff0c;很好用 但是下载来用自带的源很麻烦&#xff0c;于是就用国内的源 可以当我们添加管理仓库的时候&#xff0c;却没有了按钮&#xff0c;如何解决呢&#xff1f; 回到pycharm的主界面&#xf…

C语言:自定义类型——结构体

一、什么叫做结构体 C语⾔已经提供了内置类型&#xff0c;如&#xff1a;char、short、int、long、float、double等&#xff0c;但是只有这些内置类型还是不够的&#xff0c;假设我想描述学⽣&#xff0c;描述⼀本书&#xff0c;这时单⼀的内置类型是不⾏的。描述⼀个学⽣需要 …

Leetcode2707. 字符串中的额外字符

Every day a Leetcode 题目来源&#xff1a;2707. 字符串中的额外字符 解法1&#xff1a;动态规划 题目要求将字符串 s 分割成若干个互不重叠的子字符串&#xff08;以下简称为子串&#xff09;&#xff0c;同时要求每个子串都必须在 dictionary 中出现。一些额外的字符可能…

【EI会议征稿通知】第五届计算机通信与网络安全国际学术会议 (CCNS 2024)

第五届计算机通信与网络安全国际学术会议 (CCNS 2024) 2024 5th International Conference on Computer Communication and Network Securit IEEE Fellow、海内外高层次专家云集&#xff0c;EI、Scopus稳定检索 第五届计算机通信与网络安全国际学术会议 (CCNS 2024) 将于202…

立白科技集团:研发安全推动数字化蜕变,日化业务再上新高度

立白科技集团成立于1994年&#xff0c;是我国日化行业的领军企业&#xff0c;致力于成为一家“品牌引领、数字经营、富有创新、富有活力”的智慧服务型企业。从2018年开始&#xff0c;立白科技集团加速数字化转型&#xff0c;打造数据和业务中台&#xff0c;并建立toB和toC平台…

仿真验证方法(1)——动态验证

一、概述 1.1 验证的目的和方法 在现代集成电路设计中&#xff0c;验证所占工作量超过70%。验证要求真实而完备&#xff0c;它决定了设计的成败与成本。 验证的目的 原始描述是否正确&#xff1f;&#xff08;代码&#xff09; 逻辑功能是否正确&#xff1f;&#xff08;功能…

vue中使用mpegts.js播放flv的直播视频流

第一步&#xff1a;引入mpegts.js npm install --save mpegts.js 第二步&#xff1a;在vue文件中引入mpegts.js的依赖 第三步&#xff1a;编写展示视频的盒子 我这里是使用循环遍历的方式创建video标签&#xff0c;这样方便后面随机展示视频使用 <template><div>&l…

【前端发版】vue前端发版 步骤

1、 提交代码 代码合并通过之后到deb分支 2、git checkout 切换到dev分支上 运行起来看看自己刚刚提交的代码有没有错误 3、拉取最新代码 git pull 3、yarn run build 4、打包好的文件叫dist 重新命名为服务器里替换包名 5、登录文件传输 开始替换 替换的过程中 首先删除备…

五指CMS copyfrom.php SQL注入漏洞复现(CVE-2023-52064)

0x01 产品简介 WUZHI CMS是北京五指互联科技有限公司 的一套基于PHP和MySQL的开源内容管理系统,响应式布局,一个网站兼容多个终端 微信接口全支持,快速构建微营销平台 开放接口,支持第三方APP无缝接入。 0x02 漏洞概述 Wuzhicms 内容管理系统的/core/admin/copyfrom.p…