C++ 设计模式——解释器模式

目录

    • C++ 设计模式——解释器模式
      • 1. 主要组成成分
      • 2. 逐步构建解释器模式
        • 步骤1: 定义抽象表达式
        • 步骤2: 实现终结符表达式
        • 步骤3: 实现非终结符表达式
        • 步骤4: 构建语法树
        • 步骤5: 实现内存管理
        • 步骤6: 创建上下文和客户端
      • 3. 解释器模式 UML 图
        • UML 图解析
      • 4. 解释器模式的优点
      • 5. 解释器模式的缺点
      • 6. 解释器模式适用场景
      • 总结
      • 完整代码

C++ 设计模式——解释器模式

解释器模式是一种特定于语言的模式,用于定义如何评估语言的句法或表达式。它适用于某些重复出现的问题,可以将一个需要解释执行的语言中的句子表示为一个抽象的语法树。这种模式通常被用于开发编程语言解释器或简单的脚本引擎。

引人“解释器”设计模式的定义(实现意图):定义一个语言的文法(语法规则),并建立一个解释器解释该语言中的句子。

1. 主要组成成分

  1. 抽象表达式(Abstract Expression):定义了解释操作的接口。这个接口通常包含一个解释(Interpret)方法,该方法接受一个上下文作为参数。
  2. 终结符表达式(Terminal Expression):实现了抽象表达式接口。这些表达式代表了语言中的终结符,如数字或变量。
  3. 非终结符表达式(Nonterminal Expression):也实现了抽象表达式接口。这些表达式代表了语言中的非终结符,通常包含其他表达式。
  4. 上下文(Context):包含解释器之外的一些全局信息。这可能包括变量的值、当前状态等。
  5. 客户端(Client):构建抽象语法树并调用解释操作。客户端通常会创建或被给予一个表示特定句子的抽象语法树,然后调用解释方法。

2. 逐步构建解释器模式

这个逐步构建的过程展示了解释器模式的核心组件如何协同工作,从定义基本的表达式接口,到实现具体的表达式类,再到构建和解释复杂的表达式树。这种方法使得添加新的表达式类型变得简单,同时保持了整体结构的灵活性和可扩展性。

步骤1: 定义抽象表达式

首先定义一个抽象基类 Expression,它是所有表达式的基础,所有的具体表达式类都必须实现这个函数,以便执行具体的解释任务。

//小表达式(节点)父类
class Expression
{
public:
    Expression(int num, char sign) :m_dbg_num(num), m_dbg_sign(sign) {} //构造函数
    virtual ~Expression() {} //做父类时析构函数应该为虚函数

public:
    //解析语法树中的当前节点
    virtual int interpret(map<char, int> var) = 0; //#include <map>,map容器中的键值对用于保存变量名及对应的值

public:
    //以下两个成员变量是为程序跟踪调试时观察某些数据方便而引入
    int m_dbg_num;   //创建该对象时的一个编号,用于记录本对象是第几个创建的
    char m_dbg_sign; //标记本对象的类型,可能是个字符v代表变量(终结符表达式),也可能是个加减号(非终结符表达式)
};
步骤2: 实现终结符表达式

接着,创建一个或多个终结符表达式类,例如 VarExpression,它们直接与语言的终结符相对应。这些类实现了抽象表达式中定义的 interpret() 方法,返回变量在上下文中的值。

//变量表达式(终结符表达式)
class VarExpression :public Expression
{
public:
    VarExpression(const char& key, int num, char sign) :Expression(num, sign) //构造函数
    {
        m_key = key;
    }
    virtual int interpret(map<char, int> var)
    {
        return var[m_key];  //返回变量名对应的数值
    }

private:
    char m_key; //变量名,本范例中诸如a、b、c、d都是变量名
};
步骤3: 实现非终结符表达式

创建运算符表达式基类 SymbolExpression 和非终结符表达式类如 AddExpressionSubExpression 代表语言的规则。这些类通常会持有其他 Expression 对象,并在其 interpret() 方法中递归调用这些对象的 interpret() 方法,合并其结果。

//运算符表达式(非终结符表达式)父类
class SymbolExpression :public Expression
{
public:
    SymbolExpression(Expression* left, Expression* right, int num, char sign) :m_left(left), m_right(right), Expression(num, sign) {} //构造函数
    Expression* getLeft() { return m_left; }
    Expression* getRight() { return m_right; }
protected:
    //左右各有一个操作数
    Expression* m_left;
    Expression* m_right;
};

//加法运算符表达式(非终结符表达式)
class AddExpression :public SymbolExpression
{
public:
    AddExpression(Expression* left, Expression* right, int num, char sign) :SymbolExpression(left, right, num, sign) {}//构造函数

    virtual int interpret(map<char, int> var)
    {
        //分步骤拆开写,方便理解和观察
        int value1 = m_left->interpret(var); //递归调用左操作数的interpret方法
        int value2 = m_right->interpret(var); //递归调用右操作数的interpret方法
        int result = value1 + value2;
        return result; //返回两个变量相加的结果
    }
};

//减法运算符表达式(非终结符表达式)
class SubExpression :public SymbolExpression
{
public:
    SubExpression(Expression* left, Expression* right, int num, char sign) :SymbolExpression(left, right, num, sign) {}//构造函数

    virtual int interpret(map<char, int> var)
    {
        int value1 = m_left->interpret(var);
        int value2 = m_right->interpret(var);
        int result = value1 - value2;
        return result; //返回两个变量相减的结果
    }
};
步骤4: 构建语法树

创建一个函数来分析表达式字符串并构建语法树:

//分析—创建语法树(表达式树)
Expression* analyse(string strExp) //strExp:要计算结果的表达式字符串,比如"a-b+c+d"
{
    stack<Expression*>  expStack;//#include <stack>,这里用到了栈这种顺序容器
    Expression* left = nullptr;
    Expression* right = nullptr;
    int icount = 1;
    for (size_t i = 0; i < strExp.size(); ++i)//循环遍历表达式字符串中的每个字符
    {
        switch (strExp[i])
        {
        case '+':
            //加法运算符表达式(非终结符表达式)
            left = expStack.top(); //返回栈顶元素(左操作数)
            ++i;
            right = new VarExpression(strExp[i], icount++, 'v'); //v代表是个变量节点
            //在栈顶增加元素
            expStack.push(new AddExpression(left, right, icount++, '+')); //'+'代表是个减法运算符节点
            break;
        case '-':
            //减法运算符表达式(非终结符表达式)
            left = expStack.top(); //返回栈顶元素
            ++i;
            right = new VarExpression(strExp[i], icount++, 'v');
            expStack.push(new SubExpression(left, right, icount++, '-')); //'-'代表是个减法运算符节点
            break;
        default:
            //变量表达式(终结符表达式)
            expStack.push(new VarExpression(strExp[i], icount++, 'v'));
            break;
        } //end switch
    } //end for
    Expression* expression = expStack.top(); //返回栈顶元素
    return expression;
}
步骤5: 实现内存管理

添加一个函数来释放表达式树的内存:

void release(Expression* expression)
{
    //释放表达式树的节点内存
    SymbolExpression* pSE = dynamic_cast<SymbolExpression*>(expression); //此处代码有优化空间(不使用dynamic_cast),留给读者思考
    if (pSE)
    {
        release(pSE->getLeft());
        release(pSE->getRight());
    }
    delete expression;
}
步骤6: 创建上下文和客户端

main 函数中创建上下文(变量映射)并使用解释器:

int main()
{
    string strExp = "a-b+c+d";	 //将要求值的字符串表达式
    map<char, int> varmap;
    //下面是给字符串表达式中所有参与运算的变量一个对应的数值
    varmap.insert(make_pair('a', 7)); //类似于赋值语句a = 7
    varmap.insert(make_pair('b', 9)); //类似于赋值语句b = 9
    varmap.insert(make_pair('c', 3)); //类似于赋值语句c = 3
    varmap.insert(make_pair('d', 2)); //类似于赋值语句d = 2

    Expression* expression = analyse(strExp);  //调用analyse函数创建语法树
    int result = expression->interpret(varmap); //调用interpret接口求解字符串表达式的结果
    cout << "字符串表达式\"a - b + c + d\"的计算结果为:" << result << endl; //输出字符串表达式结果

    //释放内存
    release(expression);

    return 0;
}

3. 解释器模式 UML 图

解释器模式 UML 图

UML 图解析

解释器模式的 UML 图中包含如下 4 种角色:

  1. AbstractExpression (抽象表达式):声明了一个抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共基类。这里指Expression类。

  2. TerminalExpression (终结符表达式):抽象表达式的子类,实现了语言文法中与终结符表达式相关的解释操作。一个句子中的每个终结符表达式都是该类的一个实例,这些实例可以通过非终结符表达式组成更为复杂的句子。这里指VarExpression类。

  3. NonterminalExpression (非终结符表达式):同样是抽象表达式的子类,实现了语言文法中与非终结符表达式相关的解释操作。考虑到非终结符表达式既可以包含终结符表达式,也可以包含其他非终结符表达式,所以其相关的解释操作一般是通过递归调用实现的。这里指AddExpressionSubExpression

    注意,引入SymbolExpression类的目的是方便AddExpressionSubExpression作为其子类的编写(方便继承),SymbolExpression类本身并不是非终结符表达式,也并不是必须存在的。

  4. Context (环境类/上下文类):用于存储解释器之外的一些全局信息,例如变量名与值的映射关系、存储和访问表达式解释器的状态等。之后这个信息会作为参数传递到所有表达式的解释操作(interpret成员函数)中作为这些解释操作的公共对象来使用。可以根据实际情况决定是否需要使用该类。这里指varmap这个map容器(虽然上述范例并没有将该容器封装到一个类中)。

4. 解释器模式的优点

  1. 易于改变和扩展文法:每个文法规则都对应一个类,可以方便地改变或扩展文法。
  2. 实现文法较为容易:每条文法规则都可以表示为一个类,因此可以直接将规则表示为代码。
  3. 增加新的解释表达式较为方便:如果需要增加新的解释表达式,只需要添加一个新的类即可。

5. 解释器模式的缺点

  1. 对于复杂文法难以维护:当文法规则数目太多时,管理这些类会变得非常困难。
  2. 执行效率较低:解释器模式使用了大量的循环和递归调用,对于复杂的句子可能会导致效率问题。
  3. 可能会引起类膨胀:每个文法规则都需要一个单独的类,可能会导致系统中类的数量急剧增加。

6. 解释器模式适用场景

  1. 简单语法的语言:解释器模式非常适合用于实现一些简单的、可组合的语法规则。例如,计算器程序需要解析和计算数学表达式,可以使用解释器模式来实现。
  2. 领域特定语言(DSL):在某些领域,可能需要定义一个小型的语言来描述特定的任务或行为。例如,SQL查询、正则表达式、配置文件解析等,都可以使用解释器模式来实现相应的解析和执行。
  3. 文本处理:解释器模式可以用于文本处理和编译,例如编译器或解释器中的词法分析和语法分析。它可以将输入的文本转换为抽象语法树,并基于这个树结构执行相应的操作。
  4. 命令解释: 一些应用程序可能需要解析和执行命令行输入或脚本语言。解释器模式可以用来定义这些命令的语法,并提供相应的解释和执行机制。
  5. 规则引擎:在某些业务系统中,可能需要根据一系列规则来执行不同的操作。解释器模式可以用来定义这些规则的语法,并在运行时解析和执行这些规则。
  6. 编程语言的实现:实现一种新的编程语言或脚本语言时,解释器模式可以用于解析和执行语言的语法。许多简单的脚本语言和教学语言都使用解释器模式来实现。

总结

解释器模式提供了一种灵活的方式来解释特定语言的句子。它将每个文法规则封装到单独的类中,使得语言的解释变得模块化和可扩展。然而,这种模式在处理复杂语言时可能会导致类的数量激增,并且可能存在性能问题。因此,解释器模式最适合用于简单语言的解释,或者在需要频繁修改语法规则的场景中。在实际应用中,需要权衡其优点和缺点,并根据具体需求决定是否使用此模式。

完整代码

#include <iostream>
#include <cstring>
#include <map>
#include <stack>
#include <vector>

using namespace std;

//小表达式(节点)父类
class Expression
{
public:
    Expression(int num, char sign) :m_dbg_num(num), m_dbg_sign(sign) {} //构造函数
    virtual ~Expression() {} //做父类时析构函数应该为虚函数

public:
    //解析语法树中的当前节点
    virtual int interpret(map<char, int> var) = 0; //#include <map>,map容器中的键值对用于保存变量名及对应的值

public:
    //以下两个成员变量是为程序跟踪调试时观察某些数据方便而引入
    int m_dbg_num;   //创建该对象时的一个编号,用于记录本对象是第几个创建的
    char m_dbg_sign; //标记本对象的类型,可能是个字符v代表变量(终结符表达式),也可能是个加减号(非终结符表达式)
};

//-----
//变量表达式(终结符表达式)
class VarExpression :public Expression
{
public:
    VarExpression(const char& key, int num, char sign) :Expression(num, sign) //构造函数
    {
        m_key = key;
    }
    virtual int interpret(map<char, int> var)
    {
        return var[m_key];  //返回变量名对应的数值
    }

private:
    char m_key; //变量名,本范例中诸如a、b、c、d都是变量名
};

//------
//运算符表达式(非终结符表达式)父类
class SymbolExpression :public Expression
{
public:
    SymbolExpression(Expression* left, Expression* right, int num, char sign) :m_left(left), m_right(right), Expression(num, sign) {} //构造函数
    Expression* getLeft() { return m_left; }
    Expression* getRight() { return m_right; }
protected:
    //左右各有一个操作数
    Expression* m_left;
    Expression* m_right;
};

//加法运算符表达式(非终结符表达式)
class AddExpression :public SymbolExpression
{
public:
    AddExpression(Expression* left, Expression* right, int num, char sign) :SymbolExpression(left, right, num, sign) {}//构造函数

    virtual int interpret(map<char, int> var)
    {
        //分步骤拆开写,方便理解和观察
        int value1 = m_left->interpret(var); //递归调用左操作数的interpret方法
        int value2 = m_right->interpret(var); //递归调用右操作数的interpret方法
        int result = value1 + value2;
        return result; //返回两个变量相加的结果
    }
};

//减法运算符表达式(非终结符表达式)
class SubExpression :public SymbolExpression
{
public:
    SubExpression(Expression* left, Expression* right, int num, char sign) :SymbolExpression(left, right, num, sign) {}//构造函数

    virtual int interpret(map<char, int> var)
    {
        int value1 = m_left->interpret(var);
        int value2 = m_right->interpret(var);
        int result = value1 - value2;
        return result; //返回两个变量相减的结果
    }
};

//分析—创建语法树(表达式树)
Expression* analyse(string strExp) //strExp:要计算结果的表达式字符串,比如"a-b+c+d"
{
    stack<Expression*>  expStack;//#include <stack>,这里用到了栈这种顺序容器
    Expression* left = nullptr;
    Expression* right = nullptr;
    int icount = 1;
    for (size_t i = 0; i < strExp.size(); ++i)//循环遍历表达式字符串中的每个字符
    {
        switch (strExp[i])
        {
        case '+':
            //加法运算符表达式(非终结符表达式)
            left = expStack.top(); //返回栈顶元素(左操作数)
            ++i;
            right = new VarExpression(strExp[i], icount++, 'v'); //v代表是个变量节点
            //在栈顶增加元素
            expStack.push(new AddExpression(left, right, icount++, '+')); //'+'代表是个减法运算符节点
            break;
        case '-':
            //减法运算符表达式(非终结符表达式)
            left = expStack.top(); //返回栈顶元素
            ++i;
            right = new VarExpression(strExp[i], icount++, 'v');
            expStack.push(new SubExpression(left, right, icount++, '-')); //'-'代表是个减法运算符节点
            break;
        default:
            //变量表达式(终结符表达式)
            expStack.push(new VarExpression(strExp[i], icount++, 'v'));
            break;
        } //end switch
    } //end for
    Expression* expression = expStack.top(); //返回栈顶元素
    return expression;
}

void release(Expression* expression)
{
    //释放表达式树的节点内存
    SymbolExpression* pSE = dynamic_cast<SymbolExpression*>(expression); //此处代码有优化空间(不使用dynamic_cast),留给读者思考
    if (pSE)
    {
        release(pSE->getLeft());
        release(pSE->getRight());
    }
    delete expression;
}


int main()
{
    string strExp = "a-b+c+d";	 //将要求值的字符串表达式
    map<char, int> varmap;
    //下面是给字符串表达式中所有参与运算的变量一个对应的数值
    varmap.insert(make_pair('a', 7)); //类似于赋值语句a = 7
    varmap.insert(make_pair('b', 9)); //类似于赋值语句b = 9
    varmap.insert(make_pair('c', 3)); //类似于赋值语句c = 3
    varmap.insert(make_pair('d', 2)); //类似于赋值语句d = 2

    Expression* expression = analyse(strExp);  //调用analyse函数创建语法树
    int result = expression->interpret(varmap); //调用interpret接口求解字符串表达式的结果
    cout << "字符串表达式\"a - b + c + d\"的计算结果为:" << result << endl; //输出字符串表达式结果

    //释放内存
    release(expression);

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

生日贺卡录放音芯片,多段音频录音ic生产厂商,NVF04M-32minute

可以录音播放的生日贺卡与传统的纸质贺卡相比&#xff0c;它有着创意以及个性的特点&#xff0c;仅需少量的电子元器件&#xff0c;即可实现录音功能&#xff0c;搭配上文字&#xff0c;让声音存储在生日贺卡里&#xff0c;让贺卡也变得有温度&#xff0c;祝福我想亲口对TA说。…

fantastic-admin前端+django后端,初始化全流程记录

fantastic-admin前端是我目前看到最完善的前端框架&#xff0c;只需要简单的设置就可以快速开始项目。 但是我本人的能力有限&#xff0c;对前端知识一知半解&#xff0c;之前废了九牛二虎之力才跑通了前后端流程&#xff0c;由于新的项目需要&#xff0c;有了开发新后台的想法…

【有啥问啥】大模型应用中的哈希链推理任务

大模型应用中的哈希链推理任务 随着人工智能技术的快速发展&#xff0c;尤其是大模型&#xff08;如GPT、BERT、Vision Transformer等&#xff09;的广泛应用&#xff0c;确保数据处理和模型推理的透明性与安全性变得愈发重要。哈希链推理任务作为一种技术手段&#xff0c;能够…

学习计算机网络

a类0~127&#xff0c;b类128~191&#xff0c;c类192~223 网络地址&#xff1a;看子网掩码&#xff0c;分网络位和主机位&#xff0c;后面是主机位&#xff0c;主机位全部为0&#xff0c;网络地址。 直接广播地址&#xff1a;看子网掩码&#xff0c;分网络位和主机位&#xff…

Jenkins构建CI/CD

CI/CD 软件开发的连续方法基于自动执行脚本&#xff0c;以最大限度地减少在开发应用程序时引入错误的可能性。从新代码的开发到部署&#xff0c;它们需要较少的人为干预甚至根本不需要干预。 它涉及在每次小迭代中不断构建&#xff0c;测试和部署代码更改&#xff0c;从而减少…

vue2+ueditor集成秀米编辑器

一、百度富文本编辑器 1.首先下载 百度富文本编辑器 下载地址&#xff1a;GitHub - fex-team/ueditor: rich text 富文本编辑器 2.把下载好的文件整理好 放在图片目录下 3. 安装插件vue-ueditor-wrap npm install vue-ueditor-wrap 4.在你所需要展示的页面 引入vue-uedito…

判断给定的一个不限长的数字串大小变化趋势、经典面试题:猴子排成圈踢出求最后剩下大王编号以及Debian服务器php中安装IMAP扩展各种报错解决过程

一、判断给定的一个不限长的数字串大小变化趋势 自制了一道面试题&#xff1a;给定一个不限长的数字字符串&#xff0c;判断每一位数字的大小变化趋势是否是^或v趋势&#xff0c;如果是就返回true&#xff0c;如果不是就返回false。比如121即属于^&#xff0c;322129即属于v。这…

Verilog和Matlab实现RGB888互转YUV444

文章目录 一、色彩空间1.1 RGB色彩空间1.2 CMYK色彩空间1.3 YUV色彩空间 二、色彩空间转换公式2.1 RGB转CMYK2.2 CMYK转RGB2.3 RGB888转YUV4442.4 YUV444转RGB888 三、MATLAB实现RGB888转YUV4443.1 matlab代码3.2 matlab结果 四、Verilog实现RGB888转YUV444 一、色彩空间 色彩空…

【区块链 + 物联网】区块链边缘计算网关设备 | FISCO BCOS应用案例

目前边缘端设备主要以人工智能应用为主&#xff0c;或以数据采集网络设备为主&#xff0c;还未有区块链边缘计算网关设备&#xff0c;难以 在依托终端设备的传统行业中进行区块链 应用。本项目研制区块链边缘计算网关&#xff0c;将区块链、计算与网络集成 在一起&#xff0c;…

单片机学习笔记

一、单片机帝国的诞生与发展 1.1 单片机的基本概念 单片机是一种集成电路芯片&#xff0c;采用超大规模的集成电路把具有数据处理功能的中央处理器存储器、输入输出端口、外围电路和相关外设集成在一块硅片上构成一个小而完整的微型计算机系统。 一般而言&#xff0c;单片机也…

Java语言程序设计基础篇_编程练习题**17.21 (十六进制编辑器)

目录 题目&#xff1a;**17.21 (十六进制编辑器) 代码示例 结果展示 题目&#xff1a;**17.21 (十六进制编辑器) 编写一个 GUI 应用程序&#xff0c;让用户在文本域输入一个文件名&#xff0c;然后按回车键&#xff0c;在文本域显示它的十六进制表达形式。用户也可以修改十六…

分类预测|基于蜣螂优化极限梯度提升决策树的数据分类预测Matlab程序DBO-Xgboost 多特征输入单输出 含基础模型

分类预测|基于蜣螂优化极限梯度提升决策树的数据分类预测Matlab程序DBO-Xgboost 多特征输入单输出 含基础模型 文章目录 一、基本原理1. 数据准备2. XGBoost模型建立3. DBO优化XGBoost参数4. 模型训练5. 模型评估6. 结果分析与应用原理总结 二、实验结果三、核心代码四、代码获…

1-9 图像膨胀 opencv树莓派4B 入门系列笔记

目录 一、提前准备 二、代码详解 kernel np.ones((3, 3), np.uint8) _, binary_image cv2.threshold(image, 127, 255, cv2.THRESH_BINARY) dilated_image cv2.dilate(binary_image, kernel, iterations1) 三、运行现象 四、完整代码 五、完整工程贴出 一、提前准备 …

scrapy 爬取微博(一)【最新超详细解析】:创建微博爬取工程

本项目属于个人学习记录&#xff0c;爬取的数据会于12小时内销毁&#xff0c;且不可用于商用。 1 初始化环境 首先我们需要有python环境&#xff0c;先安装一下python&#xff0c;然后配置环境变量&#xff0c;这边给出windows的配置&#xff1a; 我这边的安装目录是D:\pyt…

PHP轻量级高性能HTTP服务框架 - webman

摘要 webman 是一款基于 workerman 开发的高性能 HTTP 服务框架。webman 用于替代传统的 php-fpm 架构&#xff0c;提供超高性能可扩展的 HTTP 服务。你可以用 webman 开发网站&#xff0c;也可以开发 HTTP 接口或者微服务。 除此之外&#xff0c;webman 还支持自定义进程&am…

Django发送邮件

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 Django 5框架Web应用开发_夏天又到了的博客-CSDN博客 本文学习怎么使用Django发送邮件。 尽管使用Python的smtplib模块发送电子邮件…

vant 动态查询下拉菜单(可用)

动态查询item项 <van-form submit"onSubmit" ref"formRef"><Title title"企业信息" title-line title-size"19" class"ml-[18px] mb-[18px]"></Title><van-cell-group inset class"py-[18px]&quo…

【JavaSE基础】Java 基础知识

Java 转义字符 Java 常用的转义字符 在控制台&#xff0c;输入 tab 键&#xff0c;可以实现命令补全 转义字符含义作用\t制表符一个制表位&#xff0c;实现对齐的功能\n &#xff1a;换行符\n换行符一个换行符\r回车符一个回车键 System.out.println(“韩顺平教育\r 北京”);&…

pod基础和镜像拉取策略

目录 pod概念 pod的分类 1.基础容器 pause 2.初始化容器 init 实验&#xff1a;定义初始化容器 init容器的作用 实验&#xff1a;如何在容器内部进行挂载 镜像拉取策略 pod概念 pod是k8s里面的最小单位&#xff0c;pod也是最小化运行容器的资源对象。容器是基于pod在k…

黑马点评10——用户签到-BitMap数据结构

文章目录 BitMap用法签到功能签到统计 BitMap用法 其实数据库完全可以实现签到功能 但签到数据比较大&#xff0c;借鉴签到卡的思想 布隆过滤器也是使用BitMap实现的. 签到功能 因为是当前用户的当天&#xff0c;所以保存需要的年月日不需要参数&#xff0c;可以直接获取。…