TypeScript:实现队列思路与写法

在实现一些功能需求时,往往会遇到一些等待进行或者依靠某个目的结束后才执行一些相关的操作。

例如:某年某月某日的某间学校正在军训中,这个学校一共有n个班,在某日内(24小时)所有班级要完成各自班级规定的体能训练。假设某班在某时进行一项体能训练,此班共有n人,排队分为n行 x n列,以下图表示:

 以上例子需要考虑的相关条件:

条件1、某学校的n个班级  可能需要考虑到校内土地不足,场地每次只能提供一个班级进行体能训练,即:一个班级进行或者多个班级进行 ,如果是一个班级进行,就是先进先出,后进后出原理。如果是多个班级进行,就是没有原理(我也不知道),根据需求不同,实现方式亦有不同,还会影响后续开发。

条件2、时间因素,是否全部班级规定n天内完成还是不存在时间因素,完成即可,每个班级完成某个体能训练需要花费的时间是多少,按单个班级进行是否能规定时间内完成,是否选择多个班级进行。

条件3、如果某个教官身体不适或者教官与学生殴打导致无法继续进行体能训练,这种情况被视为延误,是否直接移除该班级还是放到队列最后执行。

条件4、每个班的体能训练项目是否相同,还是随机抽取不同的项目进行。假设项目一样,例如执行掌上压体能训练,那么全部学生同时执行还是轮流执行。

以上例子为一个类似二维数组的队列,在实现需求时,必须考虑到所有可能,如果想得不够仔细,分分钟会重构代码结构。如果是单纯实现某个班级内学生的队列,那么考虑的不用那么多。

我简单的来搭建一个队列写法(执行完一个之后到另一个执行)。

1、首先来命名一个保存执行队列的容器

 2、命名相关的操作进程,根据自己所需保存,不需要可以不写

 3、写一个创建函数,用于触发这个队列的执行

 4、检测函数 检测是否已经完成或者正在执行中

 5、执行函数、主要执行这个操作的相关逻辑,比如以上例子中的某个学生如何进行掌上压,做了多少个掌上压,做完之后就添加一个回调函数或者发布一个事件通知已经执行完成

以上目前只是实现了一个简单一维队列的底层架构,具体思路。根据自己项目需求不同,再往里面添油加醋完成目的。以下附上我做的一个新手引导队列 一个二维数组队列作为参考

import Conf, {Guide_combinationCfg, Guide_stepCfg, GuideCfg} from "../config/Conf";
import {UIMgr} from "./UIMgr";
import {LayerMgr} from "./LayerMgr";
import {LogicDispatcher} from "../../core/event/LogicDispatcher";
import GameEvent from "../main/events/GameEvent";
import GuideEffectView from "../main/view/guide/GuideEffectView";
import GuideTouchView from "../main/view/guide/GuideTouchView";
import GuideDialogueView from "../main/view/guide/GuideDialogueView";
import GLocalStorage from "../main/global/GLocalStorage";
import Global from "../main/global/Global";

/**
 * 新手引导管理类。检测、播放、停止都在此类进行
 * @author DuckKing
 * @Date: 2019-12-18 19:53:11
 * @Last Modified by: DuckKing
 * @Last Modified time: 2019-12-30 20:45:11
 * */
export default class GuideMgr
{
    private static _instance: GuideMgr;
    public static get instance(): GuideMgr
    {
        if(!this._instance)
            this._instance = new GuideMgr();
        return this._instance;
    }

    /** 新手引导队列*/
    public list: number[] = [];
    /** 新手引导步骤队列。*/
    public steps: number[] = [];
    /** 当前要执行的新手指引id*/
    public curGuideId: number = 0;
    /** 当前执行的新手指引步骤id*/
    public curStepId: number = 0;
    /** 当前是否正在执行新手指引*/
    public curRunGuide: boolean;
    /** 当前是否正在执行某个步骤*/
    public curRunStep: boolean;

    /** 当前已打开的组件面板*/
    private _panels: {[id:  number]: GuideTouchView | GuideDialogueView | GuideEffectView } = [];

    /**
     * 检测新手引导
     * @param id
     */
    public checkGuide(id: number): void
    {
        let key: string = `${Global.heroVo.name}${GLocalStorage.GUIDE_SAVE}${id}`;
        if(!GLocalStorage.getItem(key))
        {
            let cfg: GuideCfg = Conf.guide[id];
            if(cfg) this.createGuide(id);
        }
    }

    /**
     * 创建一个新手引导
     * @param id
     */
    public createGuide(id: number): void
    {
        this.list.push(id);
        this.checkIsRunGuide();
    }

    /**
     * 检测当前是否正在执行引导
     */
    public checkIsRunGuide(): void
    {
        if(this.curRunGuide) return;

        if(this.list.length > 0)
        {
            this.curGuideId = this.list.shift();
            this.playGuide(this.curGuideId);
        }
        else
        {
            let key: string = `${Global.heroVo.name}${GLocalStorage.GUIDE_SAVE}${this.curGuideId}`;
            GLocalStorage.setItem(key, "true");
            LogicDispatcher.event(GameEvent.GUIDE_OVER);
        }
    }

    /**
     * 播放一个新手引导
     * @param guideId
     */
    public playGuide(guideId: number): void
    {
        this.curRunGuide = true;
        this.curGuideId = guideId;

        let cfg: GuideCfg = Conf.guide[guideId];
        for(let temp of cfg.steps)
        {
            this.steps.push(temp);
        }

        this.checkIsRunStep();

        LogicDispatcher.on(GameEvent.GUIDE_OVER, this, this.onGuideComplete);
    }

    /**
     * 检测当前是否正在执行步骤
     */
    public checkIsRunStep(): void
    {
        if(this.curRunStep) return;

        //检测当前是否还有步骤未执行。。若没有继续检测上一级
        if(this.steps.length > 0)
        {
            this.curStepId = this.steps.shift();
            this.playStep(this.curStepId);
        }
        else
        {
            this.curRunGuide = false;
            this.checkIsRunGuide();
        }
    }

    /**
     * 播放一个步骤
     * @param stepId 步骤id
     */
    public playStep(stepId: number): void
    {
        this.curStepId = stepId;
        this.curRunStep = true;

        let cfg: Guide_stepCfg = Conf.guide_step[stepId];
        for(let i: number = 0; i < cfg.group.length; i++)
        {
            let groupId: number = cfg.group[i];
            let std: Guide_combinationCfg = Conf.guide_combination[groupId];

            let value: any = std.value;
            let node: Laya.Node;
            if(value)
            {
                if(value.btn)
                {
                    node = UIMgr.instance.getElementHandle(LayerMgr.rootLayer, value.btn);
                }
                else if(value.list)
                {
                    node = (UIMgr.instance.getElementHandle(LayerMgr.rootLayer, value.list) as Laya.List).cells[value.index];
                }
            }

            let panel: GuideTouchView | GuideEffectView | GuideDialogueView;
            switch (std.type)
            {
                //点击面板
                case 1:
                    panel = new GuideTouchView(std, node);
                    break;
                //特效面板
                case 2:
                    panel = new GuideEffectView(std, node);
                    break;
                //战斗面板
                case 3:
                    break;
                //对白面板
                case 4:
                    panel = new GuideDialogueView(std, node);
                    break;
            }
            this._panels[std.type] = panel;
            LayerMgr.rootLayer.addChild(panel);
        }

        if(cfg.lastDelay)
        {
            Laya.timer.once(cfg.lastDelay, this, this.closePanel)
        }

        LogicDispatcher.on(GameEvent.GUIDE_STEP_OVER, this, this.onStepComplete);
    }

    /**
     * 步骤配置里面如果配置了n秒后自动关闭面板
     */
    private closePanel(): void
    {
        for(let i in this._panels)
        {
            let temp = this._panels[i];
            LayerMgr.rootLayer.removeChild(temp);
        }
        LogicDispatcher.event(GameEvent.GUIDE_STEP_OVER);
    }

    /**
     * 某个新手指引结束后的回调函数
     */
    private onGuideComplete(): void
    {
        this.curRunGuide = false;

        let that = this;
        let std: GuideCfg = Conf.guide[this.curGuideId];
        Laya.timer.once(std.startDelay ? std.startDelay : 500, this, function() {
            that.checkIsRunGuide();
        })
    }

    /**
     * 某个步骤结束后的回调函数
     */
    private onStepComplete():void
    {
        this.curRunStep = false;

        for(let i in this._panels)
        {
            let temp: GuideTouchView | GuideDialogueView | GuideEffectView = this._panels[i];
            switch (i)
            {
                case "1":
                    (temp as GuideTouchView).clear();
                    break;
                case "2":
                    break;
            }

            LayerMgr.rootLayer.removeChild(temp);
        }

        let that = this;
        let std: Guide_stepCfg = Conf.guide_step[this.curStepId];
        Laya.timer.once(std.startDelay ? std.startDelay : 500, this, function () {
            that.checkIsRunStep();
        })
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/Duck-King/p/12150004.html