设计模式学习(五):State状态模式

news2025/1/4 22:14:46

一、什么是State模式

        在面向对象编程中,是用类表示对象的。也就是说,程序的设计者需要考虑用类来表示什么东西。类对应的东西可能存在于真实世界中,也可能不存在于真实世界中。

        在State模式中,我们用类来表示状态。在现实世界中,我们会考虑各种东西的“状态”,但是几乎不会将状态当作“东西”看待。因此,可能大家很难理解“用类来表示状态”的意思。

        在本文中,我们将要学习用类来表示状态的方法。以类来表示状态后,我们就能通过切换类来方便地改变对象的状态。当需要增加新的状态时,如何修改代码这个问题也会很明确。

        用一句话来概括:State模式就是用类来表示状态。

 

二、State模式示例程序

        这里我们来看一个警戒状态每小时会改变一次的警报系统。

        功能表:

        结构图:

  

        下面我们来用程序实现这个金库警报系统。

 

2.1 伪代码

2.1.1 不使用State模式的伪代码

        刚接触到这样的需求,你会怎样设计代码呢?如果是我,我可能会这样设计:

使用金库时被调用的方法() {
    if(白天) {
        向警报中心报告使用记录
    } else if(晚上) {
        向警报中心报告紧急事态
    }
}

警铃响起时被调用的方法() {
    像警报中心报告紧急事态
}

正常通话时被调用的方法() {
    if(白天) {
        呼叫警报中心
    } else if(晚上) {
        呼叫警报中心的留言电话
    }
}

2.1.2 使用State模式的伪代码 

        并不能说上面的代码有什么不对,只是我们今天要讲的State模式是完全不同的角度,咱们一起来看看他们的区别在哪,state模式的好处在哪。

表示白天的状态的类{

    使用金库时被调用的方法() {
        向警报中心报告使用记录
    } 

    警铃响起时被调用的方法() {
        向警报中心报告紧急事态
    }

    正常通话时被调用的方法(){
        呼叫警报中心
    }
}

表示晚上的状态的类{

    使用金库时被调用的方法() {
        向警报中心报告紧急事态
    }

    警铃响起时被调用的方法() {
        向警报中心报告紧急事态
    }

    正常通话时被调用的方法(){
        呼叫警报中心的留言电话
    }
)

         大家看明白以上两种伪代码之间的区别了吗?也许此时你会说,这**也能用类来表示?

        在没有使用State模式的2.1.1中,我们会先在各个方法里面使用if语句判断现在是白天还是晚上,然后再进行相应的处理。而在使用了State模式的2.1.2中,我们用类来表示白天和晚上。这样,在类的各个方法中就不需要用if语句判断现在是白天还是晚上了。

        总结起来就是,2.1.1是用方法来判断状态,2.1.2是用类来表示状态。那么,大家能够想象出我们是如何从方法的深处挖出被埋的“状态”,将它传递给调用者的吗?

         接下来我们就来看看示例程序:

2.2 各个类之间的关系

        先来看一下所有的类和接口。

 

        再看看类图:

 

2.3 State接口 

        state接口是表示金库状态的接口。在state接口中定义了以下事件对应的接口:设置时间、使用金库、按下警铃、正常通话。

        以上这些接口分别对应我们之前在伪代码中编写的“使用金库时被调用的方法”等方法。这些方法的处理都会根据状态不同而不同。可以说,state接口是一个依赖于状态的方法的集合。

public interface State {
    //设置时间
    public abstract void doClock(Context context, int hour);
    //使用金库
    public abstract void doUse(Context context);
    //按下警铃
    public abstract void doAlarm(Context context);
    //正常通话
    public abstract void doPhone(Context context);
}

2.4 DayState类 

        Daystate类表示白天的状态。

        对于每个表示状态的类,我们都只会生成一个实例。因为如果每次发生状态改变时都生成一个实例的话,太浪费内存和时间了。为此,此处我们使用了Singleton模式

        doUse、doAlarm、doPhone分别是使用金库、按下警铃、正常通话等事件对应的方法。它们的内部实现都是调用Context中的对应方法。请注意,在这些方法中,并没有任何“判断当前状态”的if语句。在编写这些方法时,开发人员都知道“现在是白天的状态”。在State模式中,每个状态都用相应的类来表示,因此无需使用if语句或是switch语句来判断状态。

public class DayState implements State{

    //单例模式
    private static DayState singleton = new DayState();

    private DayState() {}

    public static State getInstance() {
        return singleton;
    }

    //切换白天或黑夜
    @Override
    public void doClock(Context context, int hour) {
        if (hour<9 || 17<=hour) {
            context.changeState(NightState.getInstance());
        }
    }

    //使用金库
    @Override
    public void doUse(Context context) {
        context.recordLog("使用金库(白天)");
    }

    //按下警铃
    @Override
    public void doAlarm(Context context) {
        context.callSecurityCenter("按下警铃(白天)");
    }

    //正常通话
    @Override
    public void doPhone(Context context) {
        context.callSecurityCenter("正常通话(白天)");
    }

    public String toString() {
        return "[ 白天 ]";
    }
}

 2.5 NightState类

        NightState类表示晚上的状态。它与DayState类一样,也使用了Singleton模式。Nightstate类的结构与 Daystate完全相同。

public class NightState implements State{

    private static NightState singleton = new NightState();

    private NightState() {}

    public static State getInstance() {
        return singleton;
    }

    @Override
    public void doClock(Context context, int hour) {
        if (9<=hour && hour<17) {
            context.changeState(DayState.getInstance());
        }
    }

    @Override
    public void doUse(Context context) {
        context.callSecurityCenter("紧急:晚上使用金库!");
    }

    @Override
    public void doAlarm(Context context) {
        context.callSecurityCenter("按下警铃(晚上)");
    }

    @Override
    public void doPhone(Context context) {
        context.recordLog("晚上的通话录音");
    }

    public String toString() {
        return "[ 晚上 ]";
    }
}

2.6 Context接口

        Context接口是负责管理状态和联系警报中心的接口。在介绍SafeFrame类时结合代码再说它实际进行了哪些处理。

public interface Context {
    //设置时间
    public abstract void setClock(int hour);
    //改变状态
    public abstract void changeState(State state);
    //联系警报中心
    public abstract void callSecurityCenter(String msg);
    //在警报中心留下记录
    public abstract void recordLog(String msg);
}

2.7 SafeFrame类 

        SafeFrame类是使用GUI实现警报系统界面的类( safe有“金库”的意思)。它实现了context接口。

        这里有必要说一下我们对按钮监听器的设置。我们通过调用各个按钮的addActionListener方法来设置监听器。addActionListener方法接收的参数是“当按钮被按下时会被调用的实例”,该实例必须是实现了ActionListener接口的实例。本例中,我们传递的参数是this,即SafeFrame类的实例自身(从代码中可以看到,SafeFrame类的确实现了ActionListener接口)。“当按钮被按下后,监听器会被调用”这种程序结构类似于我们在第17章中学习过的Observer模式

        还有必要说的是,在actionPerformed方法中虽然出现了if语句,但是它是用来判断“按钮的种类”的,而并非用于判断“当前状态”。请不要将我们之前说过“使用State模式可以消除if语句”误认为是“程序中不会出现任何if语句”。

public class SafeFrame extends Frame implements ActionListener, Context {

    //GUI控件
    private TextField textClock = new TextField(60);
    private TextArea textScreen = new TextArea(10, 60);
    private Button buttonUse = new Button("使用金库");
    private Button buttonAlarm = new Button("按下警铃");
    private Button buttonPhone = new Button("正常通话");
    private Button buttonExit = new Button("结束");

    //当前状态(白天或夜晚)
    private State state = DayState.getInstance();

    public SafeFrame(String title) {
        super(title);
        setBackground(Color.lightGray);
        setLayout(new BorderLayout());
        //配置textClock
        add(textClock, BorderLayout.NORTH);
        textClock.setEditable(false);
        //配置textScreen
        add(textScreen, BorderLayout.CENTER);
        textScreen.setEditable(false);
        //为界面添加按钮
        Panel panel = new Panel();
        panel.add(buttonUse);
        panel.add(buttonAlarm);
        panel.add(buttonPhone);
        panel.add(buttonExit);
        //配置界面
        add(panel, BorderLayout.SOUTH);
        //显示
        pack();
        show();
        //设置监听器
        buttonUse.addActionListener(this);
        buttonAlarm.addActionListener(this);
        buttonPhone.addActionListener(this);
        buttonPhone.addActionListener(this);
    }

    //按下按钮后该方法会被调用,在该方法中,我们会先判断当前哪个按钮被按下了,然后进行相应的处理
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(e.toString());
        if (e.getSource() == buttonUse) {
            state.doUse(this);
        } else if (e.getSource() == buttonAlarm) {
            state.doAlarm(this);
        } else if (e.getSource() == buttonPhone) {
            state.doPhone(this);
        } else if (e.getSource() == buttonExit) {
            System.exit(0);
        } else {
            System.out.println("?");
        }
    }

    //设置时间
    @Override
    public void setClock(int hour) {
        String clockstring = "现在时间是";
        if (hour < 10) {
            clockstring += "0" + hour + ":00";
        } else {
            clockstring += hour + ":00";
        }
        System.out.println(clockstring);
        textClock.setText(clockstring);
        state.doClock(this, hour);
    }

    //改变状态
    @Override
    public void changeState(State state) {
        System.out.println("从" + this.state + "状态变为了" + state + "状态。");
        this.state = state;
    }

    //联系报警中心
    @Override
    public void callSecurityCenter(String msg) {
        textScreen.append("call!" + msg + "\n");
    }

    //在报警中心留下记录
    @Override
    public void recordLog(String msg) {
        textScreen.append("record ..." + msg + "\n");
    }
}

 2.8 用于测试的Main类

        Main类生成了一个safeFrame类的实例并每秒调用一次setClock方法,对该实例设置一次时间。这相当于在真实世界中经过了一小时。 

public class Main {
    public static void main(String[] args) {
        SafeFrame frame = new SafeFrame("State Sample");
        while (true) {
            for (int hour = 0; hour < 24; hour++) {
                //设置时间
                frame.setClock(hour);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
    }
}

         程序的时序图:

三、拓展思路的要点 

3.1 分而治之

        在编程时,我们经常会使用分而治之的方针。它非常适用于大规模的复杂处理。当遇到庞大且复杂的问题,不能用一般的方法解决时,我们会先将该问题分解为多个小问题。如果还是不能解决这些小问题,我们会将它们继续划分为更小的问题,直至可以解决它们为止。分而治之,简单而言就是将一个复杂的大问题分解为多个小问题然后逐个解决。

        在State模式中,我们用类来表示状态,并为每一种具体的状态都定义一个相应的类。这样,问题就被分解了。在本章的金库警报系统的示例程序中,只有“白天”和“晚上”两个状态,可能大家对此感受不深,但是当状态非常多的时候,State模式的优势就会非常明显了。

        请大家再回忆一下前面的伪代码。在不使用State模式时,我们需要使用条件分支语句判断当前的状态,然后进行相应的处理。状态越多,条件分支就会越多。而且,我们必须在所有的事件处理方法中都编写这些条件分支语句。

        State模式用类表示系统的“状态”,并以此将复杂的程序分解开来。

3.2 依赖于状态的处理

        Main类会调用SafeFrame类的setClock方法,告诉setClock方法“请设置时间”。在setClock方法中,会像下面这样将处理委托给State类:state.doClock (this, hour) 。

        也就是说,我们将设置时间的处理看作是“依赖于状态的处理”。

        当然,不只是 doClock方法。在State接口中声明的所有方法都是“依赖于状态的处理”,都是“状态不同处理也不同”。这虽然看似理所当然,不过却需要我们特别注意。

        在State模式中,我们应该如何编程,以实现“依赖于状态的处理”呢?总结起来有如下两点。

  • 定义接口,声明抽象方法
  • 定义多个类,实现具体方法

        这就是State模式中的“依赖于状态的处理”的实现方法。

        这里故意将上面两点说得很笼统,但是,如果大家在读完这两点之后会点头表示赞同,那就意味着大家完全理解了State模式以及接口与类之间的关系。

3.3 应当是谁来管理状态迁移

        用类来表示状态,将依赖于状态的处理分散在每个ConcreteState角色中,这是一种非常好的解决办法。

        不过,在使用State模式时需要注意应当是谁来管理状态迁移。

        在示例程序中,扮演Context 角色的SafeFrame类实现了实际进行状态迁移的changeState方法。但是,实际调用该方法的却是扮演ConcreteState角色的 DayState类和NightState类。也就是说,在示例程序中,我们将“状态迁移”看作是“依赖于状态的处理”。这种处理方式既有优点也有缺点。

        优点是这种处理方式将“什么时候从一个状态迁移到其他状态”的信息集中在了一个类中。也就是说,当我们想知道“什么时候会从 DayState类变化为其他状态”时,只需要阅读DayState类的代码就可以了。

        缺点是“每个ConcreteState角色都需要知道其他ConcreteState角色”。例如,DayState类的doClock方法就使用了Nightstate类。这样,如果以后发生需求变更,需要删除NightState类时,就必须要相应地修改Daystate类的代码。将状态迁移交给ConcreteState角色后,每个ConcreteState角色都需要或多或少地知道其他ConcreteState角色。也就是说,将状态迁移交给ConcreteState角色后,各个类之间的依赖关系就会加强。

        我们也可以不使用示例程序中的做法,而是将所有的状态迁移交给扮演Context角色的SafeFrame类来负责。有时,使用这种解决方法可以提高ConcreteState角色的独立性,程序的整体结构也会更加清晰。不过这样做的话,Context角色就必须要知道“所有的ConcreteState 角色”。在这种情况下,我们可以使用Mediator模式

        当然,还可以不用State模式,而是用状态迁移表来设计程序。所谓状态迁移表是可以根据“输入和内部状态”得到“输出和下一个状态”的一览表。当状态迁移遵循一定的规则时,使用状态迁移表非常有效。

        此外,当状态数过多时,可以用程序来生成代码而不是手写代码。

3.4 不会自相矛盾

        如果不使用State模式,我们需要使用多个变量的值的集合来表示系统的状态。这时,必须十
分小心,注意不要让变量的值之间互相矛盾。而在State模式中,是用类来表示状态的。这样,我们就只需要一个表示系统状态的变量即可。

        在示例程序中,SafeFrame 类的state字段就是这个变量,它决定了系统的状态。因此,不会存在自相矛盾的状态。

3.5 易于增加新的状态

        在State模式中增加新的状态是非常简单的。以示例程序来说,编写一个XXXState类,让它实现State接口,然后实现一些所需的方法就可以了。当然,在修改状态迁移部分的代码时,还是需要仔细一点的。因为状态迁移的部分正是与其他ConcreteState角色相关联的部分

        但是,在State模式中增加其他“依赖于状态的处理”是很困难的。这是因为我们需要在State接口中增加新的方法,并在所有的ConcreteState 角色中都实现这个方法。

        虽说很困难,但是好在我们绝对不会忘记实现这个方法。假设我们现在在State接口中增加了一个doYYY方法,而忘记了在Daystate类和Nightstate类中实现这个方法,那么编译器在编译代码时就会报错,告诉我们存在还没有实现的方法。

        如果不使用State模式,就必须用if语句判断状态。这样就很难在编译代码时检测出“忘记实现方法”这种错误了(在运行时检测出问题并不难。我们只要事先在每个方法内部都加上一段“当检测到没有考虑到的状态时就报错”的代码即可)。

3.6 实例的多面性

        请注意SafeFrame类中的以下两条语句。

  •         safeFrame类的构造函数中的         buttonUse .addActionListener (this) ;
  •         actionPerformed方法中的              state.doUse (this) ;

        这两条语句中都有this。那么这个this到底是什么呢?当然,它们都是safeFrame类的实例。由于在示例程序中只生成了一个safeFrame 的实例,因此这两个this其实是同一个对象。

        不过,在addActionListener方法中和doUse方法中,对this的使用方式是不一样的。

        向addActionListener方法传递this时,该实例会被当作“实现了ActionListener接口的类的实例”来使用。这是因为addActionListener方法的参数类型是ActionListener类型。在addActionListener方法中会用到的方法也都是在ActionListener接口中定义了的方法。至于这个参数是否是safeFrame类的实例并不重要。

        向doUse方法传递this时,该实例会被当作“实现了Context接口的类的实例”来使用。这是因为douse方法的参数类型是context类型。在doUse方法中会用到的方法也都是在Context接口中定义了的方法(大家只要再回顾一下 Daystate类和Nightstate类的doUse方法就会明白了)。

        大家一定要透彻理解此处的实例的多面性。

 

四、相关的设计模式

4.1 Singleton模式

        Singleton模式常常会出现在ConcreteState角色中。在示例程序中,我们就使用了Singleton模式。这是因为在表示状态的类中并没有定义任何实例字段(即表示实例的状态的字段)。

4.2 Flyweight模式(第20章)

        在表示状态的类中并没有定义任何实例字段。因此,有时我们可以使用Flyweight模式在多个Context角色之间共享ConcreteState角色。

五、思考题

5.1、

题目

        本来应当将Context定义为抽象类而非接口,然后让Context类持有state字段,这样更符合State模式的设计思想。但是在示例程序中我们并没有这么做,而是将Context角色定义为context 接口,让safeFrame类持有state字段,请问这是为什么呢?

答案

        因为在Java中只能单一继承,所以如果将Context角色定义为类,那么由于safeFrame类已经是Frame类的子类了,它将无法再继承context类。

        不过,如果另外编写一个Context类的子类,并将它的实例保存在SafeFrame类的字段中,那么通过将处理委托给这个实例是可以实现习题中的需求的。
 

5.2、

题目:如果要对示例程序中的“白天”和“晚上”的时间区间做如下变更,请问应该怎样修改程序呢?

答案: 

        需要修改Daystate类(代码清单19-4 )以及Nightstate类(代码清单19-5)的doclock方法。

        如果事先在SafeFrame类中定义一个isDay方法和一个isNight方法,让外部可以判断当前究竞是白天还是晚上,那么就可以将白天和晚上的具体时间范围限制在safeFrame类内部。这样修改后,当时间范围发生变更时,只需要修改safeFrame类即可。

5.3、

题目:请在示例程序中增加一个新的“午餐时间(12:00~12:59)”状态。在午餐时间使用金库的话,会向警报中心通知紧急情况;在午餐时间按下警铃的话,会向警报中心通知紧急情况;在午餐时间使用电话的话,会呼叫警报中心的留言电话。
 

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

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

相关文章

【部署】Apache DolphinScheduler 伪集群部署

【部署】Apache DolphinScheduler&#xff08;海豚&#xff09; 伪集群部署&#xff08;Pseudo-Cluster&#xff09;Standalone极速体验版DolphinScheduler 伪集群部署前置准备工作本地部署环境准备 DolphinScheduler 启动环境配置用户免密及权限配置机器SSH免密登陆启动zookee…

解决bootstrap table footerFormatter表脚和表体列错位问题

需求&#xff1a;需要把表格的一列的内容在表最下面一行进行汇总&#xff0c;显示合计 实现合计步骤&#xff1a; 1.在初始化表格时&#xff0c;开启显示表脚的属性&#xff0c;如图 2.在需要合计的列中添加footerFormatter函数&#xff0c;如图 这样就会在表格最下面显示合计…

年度征文 | 再见2022,你好2023

年度征文 | 再见2022&#xff0c;你好2023题记个人简介初衷写作展望题记 这两天打开CSDN&#xff0c;发现消息栏一直提示我写这个年度征文&#xff0c;本来觉得自己没有经验可以分享&#xff0c;毕竟自己仍处于该领域的起步阶段&#xff0c;无法给大家提供有用的建议或实用的总…

功率放大器模块是什么意思(功率放大模块工作原理)

在日常电子实验测试中&#xff0c;很多电子工程师都会经常使用到功率放大器&#xff0c;随着人们对于功率放大器的频繁使用&#xff0c;对于功放的要求也越来越多&#xff0c;有些工程师就想要使用尺寸较小的仪器&#xff0c;功率放大模块便应运而生&#xff0c;今天就请安泰电…

关于几个坐标系的关系NED ENU ROS

几个坐标系转来转去&#xff0c;时间一长又搞混了。 地球固连坐标系 WND 地球固连坐标系 NED 机体坐标系 NED 惯性系 x轴在多旋翼对称平面内指向机头&#xff08;机头方向与多旋字形或X字形相关&#xff09;。 z轴在飞机对称平面内&#xff0c;垂直轴向下。然后&#xff0c;按…

从GPT到chatGPT(二):GPT2

GPT2 文章目录GPT2前言正文摘要方法概述训练数据输入表示模型结构实验语言模型Children’s Book Test&#xff08;CBT&#xff09;LAMBADAWinograd Schema Challenge&#xff08;WSC&#xff09;Reading ComprehensionSummarizationTranslationQuestion AnsweringGeneralizatio…

Linux下搭建Git服务器

目录 步骤一.安装Git&#xff1a; 步骤二.安装Gitosis 安装Gitosis依赖的工具 进入到Gitosis目录执行&#xff1a; 出现下面的信息表示安装成功 步骤三.服务器端创建git用户来管理Git服务 服务器端的Git配置公钥 步骤四.服务器端创建Git仓库 步骤五.客户端clone服务器…

PPT如何转换成PDF?三种转换方法告诉你

大家在工作中会使用PPT格式的文件来汇报工作流程吗&#xff1f;当上级领导要求你将这些工作内容全部汇总&#xff0c;并用PDF文件发给他的时候&#xff0c;你是怎么做的呢&#xff1f;是重新将内容复制黏贴到PDF文件中吗&#xff1f;今天告诉你一个简单的方法&#xff0c;其实只…

【echarts】自定义legend样式 echarts图例与⽂字对齐问题

较完整的使用介绍参考&#xff1a;https://blog.csdn.net/changyana/article/details/126281275 起因 今天使⽤echarts时发现官⽹⽰例图例部分并没有进⾏对齐&#xff0c;⼀上⼀下逼死强迫。。。 解决办法 textStyle: { // 添加height: 10, // 关键在这个height设置rich: …

前端开发-异常问题记录

Q1&#xff1a;Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示&#xff1b; 可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决 Q2&#xff1a;浏览器跨域问题&#xff08;通过配置浏览器解决&#xff09; 将chrome浏览器复制一个进行修改&#xff…

CRM如何帮助企业提高工作效率?

企业管理者在创建团队时&#xff0c;除了要凝聚人心&#xff0c;更注重效率&#xff0c;企业团队的工作效率直接决定了企业的生产力&#xff0c;生产力决定战斗力&#xff0c;使用CRM系统可以帮助企业提高工作效率。 前言 企业管理者在创建企业团队时&#xff0c;除了要凝聚人…

IOS开发基础 · SwiftUI · StanfordCS193p Lecture3-4

IOS开发Lecture3MVVMVarieties of Typesstruct & classdont care - genericsFunctionClosuresprivate(set)for函数作为参数传给函数初始化顺序Lecture4修改代码View界面预览代码修改构建View-ViewMode点击事件让bool值反转internal external nameprint("\( )")st…

NeurIPS 2022: S3GC 可扩展图聚类

talk 文章的创新性不大&#xff0c;meta-review是给了 如果还可接收&#xff0c;再考虑。 但是 本文确实是 可扩展图聚类的重要一步。已有的方法 或多或少只在 小的数据集上 进行聚类。 存在一些非聚类的通用gnn方法进行采样。本文就是利用采样降低复杂度&#xff0c;并进行大…

基于FPGA的UDP 通信(四)

引言 前文链接&#xff1a; 基于FPGA的UDP 通信&#xff08;一&#xff09; 基于FPGA的UDP 通信&#xff08;二&#xff09; 基于FPGA的UDP 通信&#xff08;三&#xff09; 本文基于FPGA与MATLAB作千兆以太网通信模块UDP数据接收实验板级验证&#xff1a;FPGA接收上位机数…

大前端 TOB 0.5 WordPress模板 漂亮大气自适应多终端多功能

tob主题基于WordPress程序&#xff0c;响应式布局支持电脑、平板和手机的完美展示。tob适用于各种图片展示网站、新闻站、电影站、美图站、资源站等等&#xff0c;扁平化设计、公众号展示、打赏功能、列表无限加载、相册功能。tob是基于WordPress程序的主题&#xff0c;由theme…

多线程与高并发(五)

【ReentrantLock源码】&#xff1a; 【AQS源码】&#xff1a; 【公平与非公平】&#xff1a; 【公平】&#xff1a; 线程想要获得一把锁&#xff0c;乖乖的去这把锁的等待队列里排队————公平。 【非公平】&#xff1a; 线程想要获得一把锁&#xff0c;不去排队&#xff0c…

嵌入式实时操作系统的设计与开发(九)

同步机制 aCoral信号量机制不仅可以实现临界资源互斥访问&#xff0c;控制系统中临界资源多个实例的使用&#xff0c;还可以用于维护线程之间、线程和中断之间的同步。 当信号量用来实现同步时&#xff0c;起始值为0&#xff0c;如一个线程正在等待某个I/O操作&#xff0c;当…

【外贸小知识】通过whatsapp获取流量的几种小方法

相信做外贸的小伙伴们对于是whatsap比较熟悉的&#xff0c;都想通过whatsapp来获取更多流量&#xff0c;更多用户。今天我们花漾灵动小编就给大家汇总了通过whatsapp获取流量的几种小方法&#xff0c;希望能对新手小白有点作用哦&#xff01;通过whatsapp获取流量的几种小方法1…

【PyTorch深度学习实践】07_Dataset和Dataloader

文章目录1. Epoch&#xff0c;Iteration&#xff0c;Batch-Size2. Dataset 和 Dataloader2.1 Dataset2.2 Dataloader2.2.1 例子2.2.2 enumerate函数3. 完整代码1. Epoch&#xff0c;Iteration&#xff0c;Batch-Size 参考博客 2. Dataset 和 Dataloader 参考博客 功能概览 2…

2023年浙江建筑八大员(标准员)精选真题题库及答案

百分百题库提供建筑八大员&#xff08;标准员&#xff09;考试试题、建筑八大员&#xff08;标准员&#xff09;考试真题、建筑八大员&#xff08;标准员&#xff09;证考试题库等,提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 14.根据《施工现场临…