【Unity程序】Unity游戏开发中常用的设计模式【一】

news2024/11/17 22:41:32

在这里插入图片描述


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创

👨‍💻 收录于专栏:Unity基础实战

🅰️



文章目录

    • 🅰️
    • 前言
    • 🎶(==1==) 常用设计模式
      • 1.单例模式
      • 2.对象池模式
      • 3.享元模式(缓存池)
      • 4.观察者模式
      • 5.代理模式
      • 6.外观模式
      • 6.工厂模式
      • 7.命令模式
    • 🎶(==2==) 设计模式Unity模板
      • 1.单例模式
      • 2.对象池模式
      • 3.享元模式(缓存池)
      • 4.观察者模式(事件中心)
      • 5.代理模式(Mediator中介)
      • 6.外观模式
    • 🎶(==3==) 程序框架
      • 1. UIManager
      • 2.UIManager中的面板基类BasePanel
    • 🅰️


前言


🎶(1 常用设计模式


1.单例模式


  • 单例模式就像是一个特殊的工厂,它确保一个类只能创建一个对象,就像是工厂只生产一种特定的产品。这种模式有助于确保在整个程序中,某个类的实例只有一个,避免了不必要的资源浪费和数据混乱。

  • 单例模式也可以类比为一个全局的管理员。它确保了在整个应用程序中只有一个实例存在,因此可以用来管理全局状态、资源、配置等,确保这些全局数据在程序中的一致性和唯一性。


2.对象池模式


  • 是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利用已有的对象来处理请求,减少频繁创建对象所占用的内存空间和初始化时间。

  • 对象池模式(Object Pool Pattern):重点在于管理可重用对象的集合,以避免频繁创建和销毁对象带来的性能开销。对象池会预先创建一定数量的对象,并在需要时将它们分配给客户端,客户端使用完毕后将对象归还给池而不是销毁。这样可以避免频繁地创建和销毁对象,提高了性能和资源利用率。


3.享元模式(缓存池)


享元模式(Flyweight Pattern):主要关注的是共享对象以减少内存占用和提高性能。它通过共享尽可能多的相似对象来减少内存使用,特别是当对象具有大量相似的状态时。它通常通过将对象的共享状态(内在状态)与对象的特定状态(外在状态)相分离来实现。


4.观察者模式


在Unity中,观察者模式是一种设计模式,用于实现对象之间的一对多依赖关系。它允许一个对象(称为主题或被观察者)将其状态的改变通知给一组依赖于该对象的其他对象(称为观察者),使得这些观察者能够自动更新。
在Unity中,观察者模式通常使用事件(Event)来实现。被观察者对象定义一个事件,并在适当的时候触发该事件。观察者对象通过订阅(Subscribe)这个事件来注册自己,一旦事件被触发,观察者对象会收到通知并执行相应的操作。

观察者模式在游戏开发中经常使用,例如在实现游戏中的事件系统、UI更新等方面。它提供了一种松耦合的方式,使得对象之间的通信更加灵活和可维护。


5.代理模式


在Unity中,代理模式是一种设计模式,用于通过创建一个代理类来控制对另一个对象的访问。代理类充当了被代理对象的中介,可以在访问被代理对象之前或之后执行一些额外的操作。

在游戏开发中,代理模式常用于以下情况:

  1. 远程代理:在网络游戏中,代理模式可以用于处理客户端和服务器之间的通信。客户端通过代理类与服务器进行通信,代理类负责将请求转发给服务器并返回响应。
  2. 虚拟代理:当处理大量资源时,可以使用代理模式来延迟创建或加载这些资源。代理类可以在需要时才实例化或加载资源,以提高程序的性能。
  3. 安全代理:代理模式可以用于实现访问控制。代理类可以根据用户的权限来控制对某些功能的访问,从而增强系统的安全性。

在Unity中,代理模式可以通过创建一个继承自某个接口的代理类来实现。代理类可以与被代理对象实现相同的接口,并在必要时调用被代理对象的方法或属性。这样,代理类就可以代替被代理对象与其他对象进行交互。


6.外观模式


在Unity中,外观模式是一种设计模式,用于提供一个统一的接口,封装了一组复杂的接口或子系统,并使其更容易使用。外观模式的目的是简化客户端与接口之间的交互,通过隐藏复杂的实现细节,提供一个简单的接口给客户端使用。

  • 在Unity中,外观模式通常用于简化复杂的系统或子系统的使用。例如,当使用Unity的物理引擎时,可以使用Rigidbody外观来处理物体的物理行为。这样,开发者可以使用简单的方法,如AddForce和Rotate,来控制物体的运动和旋转,而不必关心底层的物理计算和碰撞检测。

  • 另一个常见的使用外观模式的地方是在游戏开发中的音频管理中。通过创建一个AudioManager外观,开发者可以使用简单的方法,如PlaySound和StopSound,来控制游戏中的音频播放,而不必直接访问底层的音频引擎。

使用外观模式可以提高代码的可读性和可维护性,简化客户端代码,并且使系统更加灵活和可扩展。


6.工厂模式


在Unity中,工厂模式是一种创建型设计模式,用于封装对象的实例化过程。工厂模式将对象的创建委托给一个工厂类,该工厂类负责根据不同的条件或参数返回适当的对象实例。

  • 工厂模式的主要目的是隐藏对象的创建细节,并提供一种统一的方式来创建对象,使代码更加灵活和可维护。通过使用工厂模式,可以降低代码的耦合性,使得代码的扩展更加容易。

  • 在Unity中,工厂模式常用于创建游戏对象的实例。通过使用工厂模式,可以根据不同的需求和场景,以一种统一的方式来创建游戏对象,并在需要时对其进行初始化和配置。工厂模式可以帮助我们简化游戏对象的创建过程,提高代码的可读性和可维护性。

在Unity中,工厂模式可以通过自定义脚本和组件来实现。通过编写工厂类,可以根据不同的条件或参数来创建不同类型的游戏对象,并将其添加到场景中或作为其他对象的子对象。同时,还可以通过工厂类的接口来控制对象的创建和初始化过程,以及处理对象的销毁和回收。


7.命令模式


在Unity中,命令模式是一种设计模式,用于解耦游戏对象的行为和输入命令之间的关系。该模式通过将命令封装成对象,使得游戏对象不需要直接处理输入命令,而是通过调用命令对象来执行相应的操作。

在命令模式中,通常有四个主要的角色:

  1. 命令(Command):定义了需要执行的操作接口,通常包含一个执行方法(Execute)和一个撤销方法(Undo)。

  2. 具体命令(Concrete Command):实现了命令接口的具体类,包含了具体的操作逻辑。

  3. 命令调用者(Invoker):负责调用具体命令的对象,通常包含一个命令对象的引用。

  4. 接收者(Receiver):真正执行命令的对象,通常是游戏对象或者组件。

在Unity中,可以将输入命令封装成具体的命令对象。当玩家触发某个操作时,比如按下按钮或者触摸屏幕,命令调用者会创建相应的命令对象,并调用其执行方法。命令对象会将具体的操作逻辑委托给接收者来执行。
通过使用命令模式,可以实现游戏对象的行为和输入命令之间的解耦,提高代码的可维护性和扩展性。


🎶(2 设计模式Unity模板



1.单例模式


  • SingleManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//不继承Mono的泛型模板
public class SingleManager<T> where T:new()
{
    private static T instance;

    public static T GetInstance()
    {
        if (instance == null)
            instance = new T();
        return instance;
    }
}


  • SingletonMono
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//继承了 Mono的泛型模板 --激活只能拖拽或者AddComponent
public class SingletonMono<T> : MonoBehaviour where T: MonoBehaviour
{
    private static T instance;

    public static T GetInstance()
    {       
        return instance;
    }

    protected virtual void Awake()
    {
        instance = this as T;
    }
	
}

  • SingletonAutoMono
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


//激活--不需要拖拽或者AddComponent--直接在面板中创建
public class SingletonAutoMono<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T instance;

    public static T GetInstance()
    {
        if( instance == null )
        {
            GameObject obj = new GameObject();
           
            obj.name = typeof(T).ToString(); //设置对象的名字为脚本名

            DontDestroyOnLoad(obj);          //过场景 不移除
            instance = obj.AddComponent<T>();
        }
        return instance;
    }

}


2.对象池模式



    //音符块(栈)声明
    private Stack<NoteObject> noteObjectPool = new Stack<NoteObject>();
  /// <summary>
    /// 对象池有关
    /// </summary>
    /// <returns></returns>

    public NoteObject GetFreshNoteObject()   // 从对象池中取音符对象
    {
        NoteObject retObj;

        if (noteObjectPool.Count>0)
        {
            retObj = noteObjectPool.Pop();
        }
        else
        {
            //资源源
            //retObj = Instantiate(noteObject);
            retObj = Instantiate(noteObject);
        }

        retObj.transform.position = Vector3.one*2;
        retObj.gameObject.SetActive(true);
        //retObj.SetActive(true);
        retObj.enabled = true;

        return retObj;
    }

    public void ReturnNoteObjectToPool(NoteObject obj)  //将音符对象放入对象池
    {
        if (obj!=null)
        {
            obj.enabled = false;
            obj.gameObject.SetActive(false);
            noteObjectPool.Push(obj);
        }
    }

    /// <summary>
    /// 从特效对象池中取对象
    /// </summary>
    /// <param name="stack"></param>
    /// <param name="effectObject"></param>
    public GameObject GetFreshEffectObject(Stack<GameObject> stack,GameObject effectObject)
    {
        GameObject effectGo;

        if (stack.Count>0)
        {
            effectGo=stack.Pop();
        }
        else
        {
            effectGo = Instantiate(effectObject);
        }

        effectGo.SetActive(true);  //确保特效对象是激活状态

        return effectGo;
    }

3.享元模式(缓存池)


在这里插入图片描述

  • PoolManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;


// 抽屉数据  

public class PoolData
{

    public GameObject fatherObj;

    public List<GameObject> poolList;

    public PoolData(GameObject obj, GameObject poolObj)
    {
      
        fatherObj = new GameObject(obj.name);
        fatherObj.transform.parent = poolObj.transform;
        poolList = new List<GameObject>() {};
        PushObj(obj);
    }

    //存
    public void PushObj(GameObject obj)
    {
       
        obj.SetActive(false);
       
        poolList.Add(obj);
 
        obj.transform.parent = fatherObj.transform;
    }

    //取
    public GameObject GetObj()
    {
        GameObject obj = null;       
        obj = poolList[0];     //取第一个
        poolList.RemoveAt(0);  //然后容器中移除
       
        obj.SetActive(true);
  
        obj.transform.parent = null;     //断开了父子关系

        return obj;
    }
}

//缓存池管理器
public class PoolManager : SingleManager<PoolManager>
{
    //存储衣柜
    public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();

    private GameObject poolObj;

    //衣柜里面拿东西
    public void GetObj(string name, UnityAction<GameObject> callBack)
    {
        //有抽屉 并且抽屉里有东西
        if (poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0)
        {
            callBack(poolDic[name].GetObj());
        }
        else
        {
            //通过异步加载资源 创建对象给外部用
            ResourceManager .GetInstance().LoadAsync<GameObject>(name, (obj2) =>
            {
                obj2.name = name;
                callBack(obj2); //异步加载出的资源不能直接给外部使用所以需要委托
            });
        }
    }

    //放东西进衣柜
    public void PushObj(string name, GameObject obj)
    {
        if (poolObj == null)  //防止报错
            poolObj = new GameObject("Pool");

        //里面有抽屉
        if (poolDic.ContainsKey(name))
        {
            poolDic[name].PushObj(obj);
        }
        else
        {
            poolDic.Add(name, new PoolData(obj, poolObj));
        }
    }


   //清空缓存池——在场景切换时
    public void Clear()
    {
        poolDic.Clear();
        poolObj = null;
    }
}


4.观察者模式(事件中心)


在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public interface IEventInfo
{

}

public class EventInfo<T> : IEventInfo
{
    public UnityAction<T> actions;

    public EventInfo( UnityAction<T> action)
    {
        actions += action;
    }
}

public class EventInfo : IEventInfo
{
    public UnityAction actions;

    public EventInfo(UnityAction action)
    {
        actions += action;
    }
}

/// <summary>
/// 事件中心 单例模式对象
/// 1.Dictionary
/// 2.委托
/// 3.观察者设计模式
/// 4.泛型
/// </summary>
public class EventCenter : BaseManager<EventCenter>
{
    //key —— 事件的名字(比如:怪物死亡,玩家死亡,通关 等等)
    //value —— 对应的是 监听这个事件 对应的委托函数们
    private Dictionary<string, IEventInfo> eventDic = new Dictionary<string, IEventInfo>();

    /// <summary>
    /// 添加事件监听
    /// </summary>
    /// <param name="name">事件的名字</param>
    /// <param name="action">准备用来处理事件 的委托函数</param>
    public void AddEventListener<T>(string name, UnityAction<T> action)
    {
        //有没有对应的事件监听
        //有的情况
        if( eventDic.ContainsKey(name) )
        {
            (eventDic[name] as EventInfo<T>).actions += action;
        }
        //没有的情况
        else
        {
            eventDic.Add(name, new EventInfo<T>( action ));
        }
    }

    /// <summary>
    /// 监听不需要参数传递的事件
    /// </summary>
    /// <param name="name"></param>
    /// <param name="action"></param>
    public void AddEventListener(string name, UnityAction action)
    {
        //有没有对应的事件监听
        //有的情况
        if (eventDic.ContainsKey(name))
        {
            (eventDic[name] as EventInfo).actions += action;
        }
        //没有的情况
        else
        {
            eventDic.Add(name, new EventInfo(action));
        }
    }

    /// <summary>
    /// 移除对应的事件监听
    /// </summary>
    /// <param name="name">事件的名字</param>
    /// <param name="action">对应之前添加的委托函数</param>
    public void RemoveEventListener<T>(string name, UnityAction<T> action)
    {
        if (eventDic.ContainsKey(name))
            (eventDic[name] as EventInfo<T>).actions -= action;
    }

    /// <summary>
    /// 移除不需要参数的事件
    /// </summary>
    /// <param name="name"></param>
    /// <param name="action"></param>
    public void RemoveEventListener(string name, UnityAction action)
    {
        if (eventDic.ContainsKey(name))
            (eventDic[name] as EventInfo).actions -= action;
    }

    /// <summary>
    /// 事件触发
    /// </summary>
    /// <param name="name">哪一个名字的事件触发了</param>
    public void EventTrigger<T>(string name, T info)
    {
        //有没有对应的事件监听
        //有的情况
        if (eventDic.ContainsKey(name))
        {
            //eventDic[name]();
            if((eventDic[name] as EventInfo<T>).actions != null)
                (eventDic[name] as EventInfo<T>).actions.Invoke(info);
            //eventDic[name].Invoke(info);
        }
    }

    /// <summary>
    /// 事件触发(不需要参数的)
    /// </summary>
    /// <param name="name"></param>
    public void EventTrigger(string name)
    {
        //有没有对应的事件监听
        //有的情况
        if (eventDic.ContainsKey(name))
        {
            //eventDic[name]();
            if ((eventDic[name] as EventInfo).actions != null)
                (eventDic[name] as EventInfo).actions.Invoke();
            //eventDic[name].Invoke(info);
        }
    }

    /// <summary>
    /// 清空事件中心
    /// 主要用在 场景切换时
    /// </summary>
    public void Clear()
    {
        eventDic.Clear();
    }
}


5.代理模式(Mediator中介)


在这里插入图片描述

using PureMVC.Interfaces;
using PureMVC.Patterns.Mediator;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//-------------------------------
//-------功能:  角色面板视图中介
//-------创建者:         -------
//------------------------------

/// <summary>
/// 角色面板视图中介
/// 固定:
/// 1.继承PureMVC的Mediator脚本
/// 2.写构造函数
/// 3.重写监听通知的方法
/// 4.重写处理通知的方法
/// 5.可选:重写注册时的方法
/// </summary>
public class RoleViewMediator : Mediator
{
    //铭牌名
    public static string NAME = "RoleViewMediator";

    /// <summary>
    /// 构造函数
    /// </summary>
    public RoleViewMediator( ) : base(NAME)
    {
        //可以去写创捷面板预设体的逻辑等
    }


    /// <summary>
    /// 重写监听通知的方法,返回需要的监听(通知)
    /// </summary>
    /// <returns>返回你需要监听的通知的名字数组</returns>
    public  override string[] ListNotificationInterests()
    {
        return new string[] { 
         PureNotification.UPDATA_ROLE_INFO,
         PureNotification.ROLE_PANEL 
        };
    }

    /// <summary>
    /// 重写处理通知的方法,处理通知
    /// </summary>
    /// <param name="notification">通知</param>
    public override void HandleNotification(INotification notification)
    {
       switch (notification.Name)
        {
          case  PureNotification.UPDATA_ROLE_INFO:
                (ViewComponent as RoleView).UpdateView(notification.Body as PlayerDataObj); 
                break;
        }
    }

    /// <summary>
    /// 可选:重写注册方法(他们需要到Facde中注册)
    /// </summary>
    public override void OnRegister()
    {
        base.OnRegister();
    }

}


6.外观模式



🎶(3 程序框架


1. UIManager


其中的异步加载方法,缓冲时间很有可能会影响参数的及时传递

采用单例模式构造的UIManager脚本,对所有面板类Panel进行管理,在UIManager中

  • ①加载预制体。Canvas和所有面板都以预制体的方式进行异步加载
  • ②构建层级。并构建显示层级(Bot,Mid,Top,System) ,方便面板之间的显隐
  • ③提供面板显示、隐藏、移除和 自定义事件添加的方法

2.UIManager中的面板基类BasePanel


面板基类作为,所需面板的继承源,为其子类提供了很多便利,如下:

  • ①激活查询控件。内部构建了找寻面板中所有UI控件的方法,一激活就寻找并将其存储到字典当中
  • ②精准获取控件。可通过UI控件名字和类型,来精确得到对应UI控件(在字典中遍历)

🅰️


⭐【Unityc#专题篇】之c#进阶篇】

⭐【Unityc#专题篇】之c#核心篇】

⭐【Unityc#专题篇】之c#基础篇】

⭐【Unity-c#专题篇】之c#入门篇】

【Unityc#专题篇】—进阶章题单实践练习

⭐【Unityc#专题篇】—基础章题单实践练习

【Unityc#专题篇】—核心章题单实践练习


你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!


在这里插入图片描述


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

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

相关文章

堆溢出bug定位调试修复

最近代码出了bug&#xff0c;堆溢出。 debug下一切正常&#xff0c; release时随机崩溃到某几个地方&#xff0c; 报错是: Critical error detected c0000374 不是完全随机崩溃&#xff0c;崩溃到某几个正常的地方&#xff0c;开始怀疑是不是这几个地方真的有什么bug, 由于使…

极致产品力|从toB到toC,年销4.2亿份的冻干品牌是如何炼成的?

天野食品是日本冻干食品长红40年的品牌&#xff0c;从制造焦糖的小工厂&#xff0c;转变为日本冻干速食的行业第一&#xff0c;它是如何做到的呢? 深耕TOB业务&#xff0c;如何在ToC业务创造增长 天野公司以冻干食品闻名但并非以此起家。自1940年成立以来&#xff0c;便以染料…

智慧冶金:TSINGSEE青犀AI+视频技术助力打造高效、安全的生产环境

一、建设背景 冶金行业因其特殊的生产环境和工艺要求&#xff0c;对安全生产、环境保护以及质量监控等方面有着极高的要求。因此&#xff0c;将视频智能监控技术引入冶金行业&#xff0c;不仅有助于提升生产效率&#xff0c;更能有效保障生产安全&#xff0c;降低事故风险。 …

5.28 学习总结

一.CSS学习(一) 一、CSS简介 1、什么是CSS CSS&#xff1a;Cascading Style Sheet 层叠样式表是一组样式设置的规则&#xff0c;用于控制页面的外观样式 2、为什么使用CSS 实现内容与样式的分离&#xff0c;便于团队开发样式复用&#xff0c;便于网站的后期维护页面的精确…

跨境卖家必看!亚马逊商品3D建模怎么实现?

亚马逊引领3D内容革命&#xff0c;助力卖家提升商品展现力 亚马逊于2023年12月发布了一项重大公告&#xff0c;正式宣布&#xff1a;“平台将不再接受将360图像上传至产品详细页面的请求&#xff0c;而是全面采用3D模型来替代。”这一决策无疑预示着3D内容将在亚马逊平台上迎来…

区间类贪心,蓝桥云课 打折

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 0打折 - 蓝桥云课 (lanqiao.cn) 二、解题报告 1、思路分析 思路很简单&am…

Kubernetes(k8s) 实战集群部署Discuz x3.5 k8s使用本地私有仓库镜像 Centos 8.5 安装部署NFS

本文环境可参考: 详细教程 Centos8.5 基于 k8s v1.30.1 部署高可用集群 kubeadm 安装 kubernetes v1.30.1 docker集群搭建 延长证书有效期-CSDN博客 1 集群部署&#xff0c;需要PV&#xff0c;安装NFS #master11,slave12,slave13都安装 yum install nfs-utils rpcbind -y2 …

httphere是一个反向代理和友好前端开发的小工具

httphere 是干什么的 httphere在任意目录启动 http服务, 不仅仅是启动一个简单的http服务。 只启动http服务&#xff0c;现成的做法有&#xff1a; python2 -m SimpleHTTPServer python3 -m http.server 其他 httphere 工具httphere功能有&#xff1a;静态服器、文件上传与下…

IDEA社区版创建并运行maven管理的web项目的基本流程

一、前言 注意&#xff0c;这是社区版&#xff0c;旗舰版可以绕路。 二、过程 1、下载安装社区版 2、安装jdk&#xff0c;tomcat&#xff0c;maven 3、创建并启动项目 注意选择的骨架是maven-archetype-webapp&#xff0c;然后next&#xff0c;设置项目名&#xff0c;存放…

vivado设置Vscode为默认编辑器

D:\vscode\Microsoft VS Code\Code.exe -g [file name]:[line number]

机器学习知识与心得

目录 机器学习实践 机器学习基础理论和概念 机器学习基本方法 1.线性回归&#xff08;回归算法&#xff09; 训练集&#xff08;Training Set&#xff09; 测试集&#xff08;Test Set&#xff09; 交叉验证 正则化 特点 2.logistic回归&#xff08;分类算法&#xf…

【面试八股总结】索引(二):B+树数据结构、索引使用场景、索引优化、索引失效

参考资料&#xff1a;小林coding、阿秀 一、为什么InnoDB采用B树作为索引数据结构&#xff1f; B 树是一个自平衡多路搜索树&#xff0c;每一个节点最多可以包括 M 个子节点&#xff0c;M 称为 B 树的阶&#xff0c;所以 B 树就是一个多叉树。 B 树与 B 树的差异&#xff1a;…

数据分析必备:一步步教你如何用Pandas做数据分析(10)

1、Pandas 文本处理 Pandas 文本处理操作实例 在本章中&#xff0c;我们将使用基本的Series / Index讨论字符串操作。在随后的章节中&#xff0c;我们将学习如何在DataFrame上应用这些字符串函数。 Pandas提供了一组字符串函数&#xff0c;可以轻松地对字符串数据进行操作。最…

海信集团携纷享销客启动LTC数字化落地 推动ToB业务再升级

日前&#xff0c;海信集团携手连接型CRM纷享销客正式启动LTC&#xff08;Leads to Cash&#xff09;数字化平台实施落地项目。作为海信集团数字化的重要里程碑&#xff0c;该项目将通过统一规划、统一投资、统一平台、资源共享和数据赋能&#xff0c;构建ToB业务数字化经营管理…

System32文件夹千万不能删除,看完这篇你就知道为什么了

序言 C:\Windows\System32目录是Windows操作系统的关键部分,重要的系统文件存储在该目录中。网上的一些恶作剧者可能会告诉你删除它,但你不应该尝试去操作,如果你尝试的话,我们会告诉你会发生什么。 什么是System32文件夹 位于C:\Windows\System32的System32文件夹是所有…

【高阶数据结构】 B树 -- 详解

一、常见的搜索结构 适合做内查找&#xff1a; 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景。如果数据量很大&#xff0c;比如有 100G 数据&#xff0c;无法一次放进内存中&#xff0c;那就只能放在磁盘上了。 如果…

【C++】数据结构:哈希桶

哈希桶&#xff08;Hash Bucket&#xff09;是哈希表&#xff08;Hash Table&#xff09;实现中的一种数据结构&#xff0c;用于解决哈希冲突问题。哈希表是一种非常高效的数据结构&#xff0c;它通过一个特定的函数&#xff08;哈希函数&#xff09;将输入数据&#xff08;通常…

aws eks中cwagent收集性能日志的理解

参考资料 CloudWatch代理配置参考Prometheus的CloudWatch代理配置 本文旨在明确以下几个问题 eks的container insight addon包括哪些组件&#xff1f;分别起什么作用&#xff1f;eks的cwagent的指标获取具体包括那些部分&#xff1f;数据源是什么&#xff1f;eks的cwagent如…

【NumPy】全面解析NumPy的where函数:高效条件操作指南

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

5-26作业

网络聊天室 服务器&#xff1a; 1 #include <myhead.h>2 int main(int argc, const char *argv[])3 {4 if(argc!3)5 {6 printf("请输入IP和端口号\n");7 return -1;8 }9 int sfd socket(AF_INET, SOCK_DGRAM, 0);10 if(…