游戲框架搭建

使用框架的目標:低耦合,高內聚,表現和數據分離
耦合:對象,類的雙向引用,循環引用
內聚:相同類型的代碼放在一起
表現和數據分離:需要共享的數據放在Model里

對象之間的交互一般有三種

  1. 方法調用,A持有B才能調用B的方法
  2. 委托或回調,A持有B才能注冊B的委托,盡量避免嵌套調用
  3. 消息或事件,A不需要持有B

A調用B的方法,A就必須持有B,形成單向引用關系,為了避免耦合,B不應該引用A,如果B想調用A的方法,使用委托或回調。
總結:父節點調用子節點可以直接方法調用,子節點通知父節點用委托或事件,跨模塊通信用事件

模塊化一般有三種

  1. 單例,例如: Manager Of Managers
  2. IOC,例如: Extenject,uFrame的 Container,StrangelOC的綁定等等
  3. 分層,例如: MVC、三層架構、領域驅動分層等等

交互邏輯和表現邏輯

在這里插入圖片描述
以計數器為例,用戶操作界面修改數據叫交互邏輯,當數據變更之后或者初始化時,從Model里查詢數據在View上顯示叫表現邏輯
交互邏輯:View -> Model
表現邏輯:Model -> View

很多時候,我們不會真的去用 MVC 開發架構,而是使用表現(View)和數據(Model)分離這樣的思想,我們只要知道 View 和 Model 之間有兩種邏輯,即交互邏輯 和 表現邏輯,我們就不用管中間到底是 Controller、還是 ViewModel、還是 Presenter。只需要想清楚交互邏輯 和 交互邏輯如何實現的就可以了。

View和Model怎樣交互比較好,或者說交互邏輯和表現邏輯怎樣實現比較好?

<1> 直接方法調用,表現邏輯是在交互邏輯完成之后主動調用,偽代碼如下

public class CounterViewController : MonoBehaviour
{void Start(){transform.Find("BtnAdd").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯CounterModel.Count++;// 表現邏輯UpdateView();});transform.Find("BtnSub").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯CounterModel.Count--;// 表現邏輯UpdateView();});// 表現邏輯UpdateView();}void UpdateView(){transform.Find("CountText").GetComponent<Text>().text = CounterModel.Count.ToString();}
}public static class CounterModel
{public static int Count = 0;
}

<2> 使用委托

public class CounterViewController : MonoBehaviour
{void Start(){// 注冊CounterModel.OnCountChanged += OnCountChanged;transform.Find("BtnAdd").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯:這個會自動觸發表現邏輯CounterModel.Count++;});transform.Find("BtnSub").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯:這個會自動觸發表現邏輯CounterModel.Count--;});OnCountChanged(CounterModel.Count);}// 表現邏輯private void OnCountChanged(int newCount){transform.Find("CountText").GetComponent<Text>().text = newCount.ToString();}private void OnDestroy(){// 注銷CounterModel.OnCountChanged -= OnCountChanged;}
}public static class CounterModel
{private static int mCount = 0;public static event Action<int> OnCountChanged ;public static int Count{get => mCount;set{if (value != mCount){mCount = value;OnCountChanged?.Invoke(value);}}}
}

<3> 使用事件,事件管理器寫法差不多,這里忽略具體實現

public class CounterViewController : MonoBehaviour
{void Start(){// 注冊EventManager.Instance.RegisterEvent(EventId, OnCountChanged);transform.Find("BtnAdd").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯:這個會自動觸發表現邏輯CounterModel.Count++;});transform.Find("BtnSub").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯:這個會自動觸發表現邏輯CounterModel.Count--;});OnCountChanged();}// 表現邏輯private void OnCountChanged(){transform.Find("CountText").GetComponent<Text>().text = CounterModel.Count.ToString();}private void OnDestroy(){// 注銷EventManager.Instance.UnRegisterEvent(EventId, OnCountChanged);}
}public static class CounterModel
{private static int mCount = 0;public static int Count{get => mCount;set{if (value != mCount){mCount = value;// 觸發事件EventManager.Instance.FireEvent(EventId);}}}
}

比較上面3種實現方式,當數據量很多的時候,使用第1種方法調用會寫很多重復代碼調用,代碼臃腫,容易造成疏忽,使用委托或事件代碼更精簡,當數據變化時會自動觸發表現邏輯,這就是所謂的數據驅動。

所以表現邏輯使用委托或事件更合適,如果是單個數值變化,用委托的方式更合適,比如金幣、分數、等級、經驗值等等,如果是顆粒度較大的更新用事件比較合適,比如從服務器拉取了一個任務列表數據,然后任務列表數據存到了Model

BindableProperty

上面的Model類,每新增一個數據就要寫一遍類似的代碼,很繁瑣,我們使用泛型來簡化代碼

public class BindableProperty<T> where T : IEquatable<T>
{private T mValue;public T Value{get => mValue;set{if (!mValue.Equals(value)){mValue = value;OnValueChanged?.Invoke(value);}}}public Action<T> OnValueChanged;
}

BindableProperty 也就是可綁定的屬性,是 數據 + 數據變更事件 的合體,它既存儲了數據充當 C# 中的 屬性這樣的角色,也可以讓別的地方監聽它的數據變更事件,這樣會減少大量的樣板代碼

public class CounterViewController : MonoBehaviour
{void Start(){// 注冊CounterModel.Count.OnValueChanged += OnCountChanged;transform.Find("BtnAdd").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯:這個會自動觸發表現邏輯CounterModel.Count.Value++;});transform.Find("BtnSub").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯:這個會自動觸發表現邏輯CounterModel.Count.Value--;});OnCountChanged(CounterModel.Count.Value);}// 表現邏輯private void OnCountChanged(int newValue){transform.Find("CountText").GetComponent<Text>().text = newValue.ToString();}private void OnDestroy(){// 注銷CounterModel.Count.OnValueChanged -= OnCountChanged;}
}public static class CounterModel
{public static BindableProperty<int> Count = new BindableProperty<int>(){Value = 0};
}

總結:

  • 自頂向下的邏輯使用方法調用
  • 自底向上的邏輯使用委托或事件,Model和View是底層和上層的關系,所以用委托或事件更合適

Command

實際的開發中交互邏輯的代碼是很多的,隨著功能需求越來越多,Controller的代碼會越來越臃腫,解決辦法是引入命令模式(Command),命令模式參考另一篇博客:Unity常用設計模式
先定義一個接口

public interface ICommand
{void Execute();
}

添加一個命令,實現數據加一操作,注意這里是用 struct 實現的,而不是用的 class,這是因為游戲里邊的交互邏輯有很多,如果每一個都用去 new 一個 class 的話,會造成很多性能消耗,比如 new 一個對象所需要的尋址操作、比如對象回收需要的 gc 等等,而 struct 內存管理效率要高很多

public struct AddCountCommand : ICommand
{public void Execute(){CounterModel.Count.Value++;}
}

實現數據減一操作

public struct SubCountCommand : ICommand
{public void Execute(){CounterModel.Count.Value--;}
}

更新交互邏輯的代碼

    public class CounterViewController : MonoBehaviour{void Start(){// 注冊CounterModel.Count.OnValueChanged += OnCountChanged;transform.Find("BtnAdd").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯new AddCountCommand().Execute();});transform.Find("BtnSub").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯new SubCountCommand().Execute();});OnCountChanged(CounterModel.Count.Value);}// 表現邏輯private void OnCountChanged(int newValue){transform.Find("CountText").GetComponent<Text>().text = newValue.ToString();}private void OnDestroy(){// 注銷CounterModel.Count.OnValueChanged -= OnCountChanged;}}public static class CounterModel{public static BindableProperty<int> Count = new BindableProperty<int>(){Value = 0};}

使用 Command 符合讀寫分離原則(Comand Query Responsibility Segregation),簡寫為 CQRS ,這個概念在 StrangeIOC、uFrame、PureMVC、Loxodon Framework 都有實現,而在微服務領域比較火的 DDD(領域驅動設計)的實現一般也會實現 CQRS。它是一種軟件架構模式,旨在將應用程序的讀取和寫入操作分離為不同的模型。在CQRS中,寫操作通常由命令模型(Command Model)來處理,它負責處理業務邏輯和狀態更改。而讀操作則由查詢模型(Query Model)來處理,它專門用于支持數據查詢和讀取展示。

Command 模式就是邏輯的調用和執行是分離的,我們知道一個方法的調用和執行是不分離的,因為一旦你調用方法了,方法也就執行了,而 Command 模式能夠做到調用和執行在空間和時間上是能分離的。

空間分離的方法就是調用的地方和執行的地方放在兩個文件里。
時間分離的方法就是調用的之后,Command 過了一點時間才被執行。

Command 分擔 Controller 的交互邏輯,由于有了調用和執行分離這個特點,所以我們可以用不同的數據結構去組織 Command 調用,比如列表,隊列,棧

在這里插入圖片描述
底層系統層是可以共享給別的展現層使用的,切換表現層非常方便,表現層到系統層用 Command 改變底層系統的狀態(數據),系統層通過事件或者委托通知表現層,在通知的時候可以推送數據,也可以讓表現層收到通知后自己去查詢數據。

模塊化

使用單例

單例比靜態類好一點就是其生命周期相對可控,而且訪問單例對象比訪問靜態類多了一點限制,也就是需要通過 Instance 獲取

每個模塊繼承 Singleton

public class Singleton<T> where T : class
{public static T Instance{get{if (mInstance == null){// 通過反射獲取構造var ctors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);// 獲取無參非 public 的構造var ctor = Array.Find(ctors, c => c.GetParameters().Length == 0);if (ctor == null){throw new Exception("Non-Public Constructor() not found in " + typeof(T));}mInstance = ctor.Invoke(null) as T;}return mInstance;}}private static T mInstance;
}

問題:單例沒有訪問限制,容易造成模塊之間互相引用,關系混亂

IOC容器

IOC 容器可以理解為是一個字典,這個字典以 Type 為 key,以對象即 Instance 為 value,IOC 容器最少有兩個核心的 API,即根據 Type 注冊實例,根據 Type 獲取實例

public class IOCContainer
{/// <summary>/// 實例/// </summary>public Dictionary<Type, object> mInstances = new Dictionary<Type, object>();/// <summary>/// 注冊/// </summary>/// <param name="instance"></param>/// <typeparam name="T"></typeparam>public void Register<T>(T instance){var key = typeof(T);if (mInstances.ContainsKey(key)){mInstances[key] = instance;}else{mInstances.Add(key,instance);}}/// <summary>/// 獲取/// </summary>public T Get<T>() where T : class{var key = typeof(T);object retObj;if(mInstances.TryGetValue(key,out retObj)){return retObj as T;}return null;}
}

下面是一個簡單的示例,IOC 容器創建,注冊實際應當寫在游戲初始化時,這里為了方便演示都寫在一起了

public class IOCExample : MonoBehaviour
{void Start(){// 創建一個 IOC 容器var container = new IOCContainer();// 注冊一個藍牙管理器的實例container.Register(new BluetoothManager());// 根據類型獲取藍牙管理器的實例var bluetoothManager = container.Get<BluetoothManager>();//連接藍牙bluetoothManager.Connect();}public class BluetoothManager{public void Connect(){Debug.Log("藍牙連接成功");}}
}

為了避免樣板代碼,這里創建一個抽象類

/// <summary>
/// 架構
/// </summary>
public abstract class Architecture<T> where T : Architecture<T>, new()
{#region 類似單例模式 但是僅在內部課訪問private static T mArchitecture = null;// 確保 Container 是有實例的static void MakeSureArchitecture(){if (mArchitecture == null){mArchitecture = new T();mArchitecture.Init();}}#endregionprivate IOCContainer mContainer = new IOCContainer();// 留給子類注冊模塊protected abstract void Init();// 提供一個注冊模塊的 APIpublic void Register<T>(T instance){MakeSureArchitecture();mArchitecture.mContainer.Register<T>(instance);}// 提供一個獲取模塊的 APIpublic static T Get<T>() where T : class{MakeSureArchitecture();return mArchitecture.mContainer.Get<T>();}
}

子類注冊多個模塊

public class PointGame : Architecture<PointGame>
{// 這里注冊模塊protected override void Init(){Register(new GameModel1());Register(new GameModel2());Register(new GameModel3());Register(new GameModel4());}
}

使用 IOC 容器的目的是增加模塊訪問的限制

除了可以用來注冊和獲取模塊,IOC 容器一般還會有一個隱藏的功能,即:注冊接口模塊

public class IOCExample : MonoBehaviour
{void Start(){// 創建一個 IOC 容器var container = new IOCContainer();// 根據接口注冊實例container.Register<IBluetoothManager>(new BluetoothManager());// 根據接口獲取藍牙管理器的實例var bluetoothManager = container.Get<IBluetoothManager>();//連接藍牙bluetoothManager.Connect();}/// <summary>/// 定義接口/// </summary>public interface IBluetoothManager{void Connect();}/// <summary>/// 實現接口/// </summary>public class BluetoothManager : IBluetoothManager{public void Connect(){Debug.Log("藍牙連接成功");}}
}

抽象-實現 這種形式注冊和獲取對象的方式是符合依賴倒置原則的。
依賴倒置原則(Dependence Inversion Principle):程序要依賴于抽象接口,不要依賴于具體實現。依賴倒置原則是 SOLID 中的字母 D。

這種設計的好處:

  • 接口設計與實現分成兩個步驟,接口設計時可以專注于設計,實現時可以專注于實現。
  • 實現是可以替換的,比如一個接口叫 IStorage,其實現可以是 PlayerPrefsStorage、EdtiroPrefsStorage,等切換時候只需要一行代碼就可以切換了。
  • 比較容易測試(單元測試等)
  • 降低耦合。
接口的顯式實現
public interface ICanSayHello
{void SayHello();void SayOther();
}public class InterfaceDesignExample : MonoBehaviour, ICanSayHello
{/// <summary>/// 接口的隱式實現/// </summary>public void SayHello(){Debug.Log("Hello");}/// <summary>/// 接口的顯式實現,不能寫訪問權限關鍵字/// </summary>void ICanSayHello.SayOther(){Debug.Log("Other");}void Start(){// 隱式實現的方法可以直接通過對象調用this.SayHello();// 顯式實現的接口不能通過對象調用// this.SayOther() // 會報編譯錯誤// 顯式實現的接口必須通過接口對象調用(this as ICanSayHello).SayOther();}
}

當需要實現多個簽名一致的方法時,可以通過接口的顯式聲明來區分到底哪個方法是屬于哪個接口的
利用接口的顯示實現,子類想要調用必須先轉成接口,這樣就增加了調用顯式實現的方法的成本,所以可以理解為這個方法被閹割了

分層

前面使用 Command 分擔了 Controller 的交互邏輯的部分邏輯,并不是所有的交互邏輯都適合用 Command 來分擔的,還有一部分交互邏輯是需要交給 System 層來分擔。這里 System 層在概念等價于游戲的各個管理類 Manager。
Command 是沒有狀態的,有沒有狀態我們可以理解為這個對象需不需要維護數據,因為 Command 類似于是一個方法,只要調用然后執行一次就可以不用了,所以 Command 是沒有狀態的

梳理一下當前的架構

  • 表現層:即 ViewController 或者 MonoBehaviour 腳本等,負責接受用戶的輸入,當狀態變化時更新表現
  • System 層:系統層,有狀態,在多個表現層共享的邏輯,負責即提供 API 又有狀態的對象,比如網絡服務、藍牙服務、商城系統等,也支持分數統計、成就系統這種硬編碼比較多又需要把代碼放在一個位置的需求。
  • Model 層:管理數據,有狀態,提供數據的增刪改查。
  • Utility 層:工具層,無狀態,提供一些必備的基礎工具,比如數據存儲、網絡鏈接、藍牙、序列化反序列化等。

表現層改變 System、Model 層級的狀態用 Command,System 層 和 Model 層 通知 表現層用事件,委托或 BindableProeprty,表現層查詢狀態時可以直接獲取 System 和 Model 層

每個層級都有一些規則:

表現層

  • 可以獲取 System
  • 可以獲取 Model
  • 可以發送 Command
  • 可以監聽 Event

系統層

  • 可以獲取其他 System
  • 可以獲取 Model
  • 可以監聽,發送 Event
  • 可以獲取 Utility

數據層

  • 可以獲取 Utility
  • 可以發送 Event

工具層

  • 啥都干不了,可以集成第三方庫,或者封裝 API

除了四個層級,還有一個核心概念就是 Command

Command

  • 可以獲取 System
  • 可以獲取 Model
  • 可以獲取 Utility
  • 可以發送 Event
  • 可以發送其他 Command

貧血模型和充血模型

在這里插入圖片描述
我們有一個 User 對象,偽代碼如下

public class User
{public string Name {get;set;}public int Age {get;set;}public string Id {get;set;}public string NickName {get;set;public float Weight {get;set;}
}

總共有五個屬性,但是在表現層的界面中,只需要顯示三個屬性,即:姓名 Name、年齡 Age、和 Id。
表現層查詢一個用戶數據的時候,返回了一個 完整的 User 對象,這種數據流向模型叫做貧血模型。就是表現層需要用到的數據結果給了一整個未經過篩選的數據對象過來。

在這里插入圖片描述
定義了一個 UserInfo 類,偽代碼如下;

public class UserInfo
{public string Name {get;set;}public int Age {get;set;}public string Id {get;set;}
}

充血模型就是表現層需要哪些數據,就剛好返回哪些數據

充血模型 比 貧血模型 需要做跟多的工作,寫更多的代碼,甚至還有跟多的性能消耗。
但是在越大規模的項目中 充血模型 的好處就會更加明顯。因為充血模型,可以讓我們的代碼更精確地描述業務,會提高代碼的可讀性,而貧血模型,會讓我們的數據逐漸趨于混亂。

參考

涼鞋 《框架搭建 決定版》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/717071.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/717071.shtml
英文地址,請注明出處:http://en.pswp.cn/news/717071.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

跨平臺指南:在 Windows 和 Linux 上安裝 OpenSSL 的完整流程

Windows安裝 一&#xff1a;找到安裝包&#xff0c;雙擊即可 https://gitee.com/wake-up-again/installation-package.git 二&#xff1a;按照提示&#xff0c;一步一步來&#xff0c;就可以啦 三&#xff1a;此界面意思是&#xff0c;是否想向創作者捐款&#xff0c;自己視情…

2024最新搭建Mybatis配置教程【超詳細】

為什么要學習mybatis 首先要弄清楚什么是mybatis&#xff1f;我們為什么要學mybatis 學習MyBatis可以幫助開發人員更高效地進行數據庫操作&#xff0c;提高開發效率&#xff0c;并且可以使得應用程序更具可維護性和性能優勢。 我們知道Java程序操作數據庫是通過jdbc與數據庫進…

藍橋杯——矩形拼接

矩形拼接 題目分析 對于一個矩形而言&#xff0c;我可以把它橫著放&#xff0c;而可以把它豎著放&#xff0c;比如下圖&#xff0c; 3個矩形的拼接情況可以通過在紙上畫圖模擬出來&#xff0c;情況有以下三種 ? 圖1 圖3是4條邊&#xff0c;即四邊形。觀察一下什么時候會是四…

IO(Linux)

文件系統 前言1. 回顧關于C文件部分函數2. 一些文件知識的共識3. 相對路徑4. fwrite中的\0 一、文件描述符fd1. 概念2. 系統調用① open 和 close② write③ read 和 lseek 3. 缺省打開的fd 二、重定向1. 原理2. 系統調用dup23. stdout和stderr的區別4. 進程替換和原來進程文件…

【計算機考研】408學到什么程度才能考130?

408考130要比考研數學考130難的多 我想大部分考過408的考生都是這么認為的。408的難點在于他涉及的范圍太廣了&#xff0c;首先如果你要備考408&#xff0c;你要準備四門課程&#xff0c;分別是數據結構&#xff0c;計算機組成原理&#xff0c;操作系統和計算機網絡。 這四門…

kafka學習筆記四(面試題)

[Kafka 常見面試題]如何保證消息的不重復不丟失-阿里云開發者社區 (aliyun.com) 18道kafka高頻面試題哪些你還不會&#xff1f;&#xff08;含答案和思維導圖&#xff09;-阿里云開發者社區 (aliyun.com) Leader Epoch機制解決的是數據丟失或不一致的問題&#xff0c;見下文&…

報錯解決:av.codec.codec.UnknownCodecError: libx264

1. 錯誤信息 今天在使用Pytorch.io和PyAV包的時候出現了這個錯誤&#xff0c;完整的錯誤信息如下所示&#xff1a; ...envs\tf2_py38\lib\site-packages\torchvision\io\video.py", line 92, in write_videostream container.add_stream(video_codec, ratefps)File &qu…

企業計算機服務器中了360勒索病毒如何解密,360后綴勒索病毒處理流程

對于眾多的企業來說&#xff0c;企業的數據是企業發展的核心&#xff0c;越來越多的企業開始注重企業的數據安全問題&#xff0c;但隨著網絡技術的不斷發展與應用&#xff0c;網絡黑客的攻擊加密手段也在不斷升級。近期&#xff0c;云天數據恢復中心接到多家企業的求助&#xf…

設計模式—命令模式:探索【命令模式】的奧秘與應用實踐!

命令模式 命令模式是一種行為設計模式&#xff0c;它的主要目的是將請求封裝成一個對象&#xff0c;從而使得請求的發送者和接收者之間進行解耦。 在命令模式中&#xff0c;命令被封裝為一個對象&#xff0c;包含了需要執行的操作以及執行這些操作所需的所有參數。 命令的發送者…

【藍橋杯】2023省賽真題詳解(更新中)

&#x1f40f;小憐憐的簡介&#xff1a; &#x1f496;博客主頁&#xff1a;浣熊小憐憐 &#x1f680;年齡&#xff1a;23 大三在讀 &#x1f4aa;愛好&#xff1a;干飯&#xff0c;運動&#xff0c;碼代碼&#xff0c;看書&#xff0c;音樂 &#x1f389;歡迎關注&#x1f50d…

Vue3 v-for循環獲取不到圖片路徑問題

解決辦法 <span>{{item.title}}</span> 通過本地靜態文件獲取img的地址即可展示圖片 url:"/src/assets/comImgs/txt1.png",

OpenGuass 之 where 1 = 0 處理流程代碼走讀

一. 前言 在OpenGuass中&#xff0c;如果where 條件中包含where 1 0 等固定為否條件的查詢語句&#xff0c;在生成執行計劃的時候&#xff0c;執行計劃是BaseResult類型&#xff0c;此類型的執行計劃不會進行物理數據掃描&#xff0c;如下所示&#xff1a; 對于非固定為否條件&…

【論文閱讀】多傳感器SLAM數據集

一、M2DGR 該數據集主要針對的是地面機器人&#xff0c;文章正文提到&#xff0c;現在許多機器人在進行定位時&#xff0c;其視角以及移動速度與車或者無人機有著較大的差異&#xff0c;這一差異導致在地面機器人完成SLAM任務時并不能直接套用類似的數據集。針對這一問題該團隊…

latex中\documentclass[preprint,review,12pt]{elsarticle}的詳細解釋

在LaTeX中&#xff0c;\documentclass 是一個命令&#xff0c;用于指定文檔所使用的文檔類。文檔類定義了文檔的總體結構、格式和樣式。elsarticle 是一個常用的文檔類&#xff0c;它主要用于在Elsevier出版的期刊上提交論文。 詳細解釋 \documentclass[preprint,review,12pt…

Autosar Appl介紹

AUTOSAR架構中的應用層 AUTOSAR 應用層構成AUTOSAR 架構中的最頂層,被認為對所有車輛應用至關重要。AUTOSAR 標準使用“組件”概念指定應用層實現。 在談論應用層實現時,應該考慮的三個最重要的部分是: AUTOSAR 應用軟件組件這些組件的 AUTOSAR 端口AUTOSAR 端口接口 AUTOS…

浙江大學主辦!2024年第7屆信息通信與信號處理國際會議( ICICSP2024)征稿開啟!

會議官網 IEEE | ICICSP 2024 學術會議查詢-學術會議交流服務平臺-愛科會易 (uconf.com)?www.uconf.com/

FreeSWITCH 1.10.10 簡單圖形化界面16 - ubuntu22.04編譯mod_python3時遇到的問題記錄

FreeSWITCH 1.10.10 簡單圖形化界面16 - 編譯mod_python3時遇到的問題 0、 界面預覽1、編譯mod_python3時報錯2、解決參考FreeSWITCH界面安裝參考:https://blog.csdn.net/jia198810/article/details/132479324 0、 界面預覽 http://myfs.f3322.net:8020/ 用戶名:admin,密碼…

OpenChat:性能高達105.7%,第一個超越ChatGPT的開源模型?

OpenChat&#xff1a;性能高達105.7%&#xff0c;第一個超越ChatGPT的開源模型&#xff1f; 前幾天開源模型第一還是是Vicuna-33B、WizardLM&#xff0c;這不又換人了。對于開源模型的風起云涌&#xff0c;大家見怪不怪&#xff0c;不斷更新的LLM榜單似乎也沒那么吸引人了。 …

在springboot項目中調用通義千問api多輪對話并實現流式輸出

官網文檔 阿里靈積提供了詳細的官方文檔 如何實現多輪對話 官方文檔中提到只需要把每輪對話中返回結果添加到消息管理器中&#xff0c;就可以實現多輪對話。本質上就是將歷史對話再次發送給接口。 如何實現流式輸出 官方文檔中提出使用streamCall()方法就可以實現流式輸出&…

ViT的若干細節

之前只看了ViT的大概結構&#xff0c;具體的模型細節和代碼實現知之甚少。隨著ViT逐漸成為CV領域的backbone&#xff0c;有必要重新審視下。 patch -> token 為了將圖片處理成序列格式&#xff0c;很自然地想到將圖片分割成一個個patch&#xff0c;再把patch處理成token。 …