成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

跨桌面端之組件化實踐

移動開發 新聞
本文主要介紹了千牛PC跨端框架中,我們關于組件化部分的思考、方案選擇、遇到的一些問題和解法。

背景介紹

windows千牛功能很豐富,mac千牛什么時候可以把能力對齊?

相信所有跨平臺應用,都有遇到過這樣的窘境。由于平臺差異的復雜性,維護多端產品成本非常高,且常常存在多端體驗不一致的問題。情況就是這樣,而我們團隊維護了pc千牛和pc旺旺2款跨端產品,在效能和體驗的雙重壓力之下,搭建一個多端統一的pc應用跨平臺開發框架勢在必行。

本文主要介紹了千牛PC跨端框架中,我們關于組件化部分的思考、方案選擇、遇到的一些問題和解法。

所謂框架,它既是一個“框子”,有一定的約束性,也是一個“架子”,有一定的支撐性。IT語境中的框架,特指為解決一個開放性問題而設計的具有一定約束性的支撐結構。在此結構上可以根據具體   問題擴展、安插更多的組成部分,從而更迅速和方便地構建完整的解決問題的方案。

為什么要做組件化?

跨端框架為什么選擇做組件化?

框架本身一般不能直接解決某個具體問題,但為解決問題的相關組件提供了一些銜接、組合的基礎能力。

框架的科學性、易用性,直接決定了研發效率和產品質量。

組件化是用來解決框架功能擴展、復用的一種非常合適的技術方案。

而用組件化模式設計的一個應用框架,一般具備以下特性:

  1. 極好的擴展性
  2. 極好的復用性
  3. 靈活度高,可以很方便組裝或下線功能
  4. 修改功能,影響范圍很小
  5. 非常適合團隊分工協作

這些優點,每一項都是我們夢寐以求的,所以說組件化對我們幾乎是必然選擇。

組件化是什么?

組件化是指解耦復雜系統時將多個功能模塊拆分、重組的過程,有多種屬性、狀態反映其內部特性。

舉個例子,你要造一個汽車,但是發現汽車實在太復雜了,很難實現,于是:

  1. 你把汽車拆分成了底盤,發動機,變速箱,輪子等模塊,定義好了他們各自的職責。
  2. 然后你找來小伙伴幫忙,先約定好了組件標準,再讓每個人實現其中一個獨立模塊。
  3. 你還需要一個控制系統,能夠讓這些模塊互相配合,協同工作。
  4. 由于大家都按照一個標準來開發,這些模塊很容易被組裝到一起,進行管理和控制。
  5. 這樣,你們實現了一個汽車。

這里的一個功能模塊,就是一個組件,用來控制組件協作運行的系統,就是組件框架。

組件框架需要解決的幾個問題:

  1. 如何發現組件
  2. 如何管理組件的生命周期
  3. 如何組件間調用
  4. 提供的公共基礎能力

圖片

怎么選擇組件化方案?

組件化的落地方案很多,我們怎么選擇適合自己的技術方案?

業界的組件化方案很多,例如windows下的com組件,andriod下的ARouter組件,基于消息總線的ths組件,千牛自研的prg::com組件,還有一些基于rpc框架,更寬泛意義上組件化(微服務)。

在我看來,組件化方案沒有最好的,只有相對合適的。根據業務場景,選擇一個滿足當前業務需要,又能適當照顧到未來發展需要,好用好維護的方案就可以。

這里提供一些組件化方案選型一些可參考的維度:

  1. 發現機制
  2. 通信機制
  3. 跨平臺
  4. 跨編程語言
  5. 維護成本
  6. 研發效率
  7. 編譯依賴
  8. 性能
  9. 穩定性

圖片

在跨端千牛的場景下,我們的訴求優先級是:

  1. 首先必須是支持跨平臺的,
  2. 其次是良好的可維護性,長期來看,可維護性對產品質量、效能和研發體驗都影響深遠。
  3. 然后是良好的性能和穩定性,
  4. 最后是較好的研發效能和研發體驗。

這里我們主要對比了ths組件和prg::com組件方案:

  1. ths組件:ths方案類似于一個rpc調用框架,所有調用以消息的形式在總線上傳遞,其運行時隔離&有中心節點切面,但其接口可維護性較差,無法在編譯期發現問題。ths方案更適合跨團隊場景,或開放場景。
  2. prg::com組件:prg::com組件類似于微軟的com組件,但它支持了跨平臺,并對com接口調用方式進行了優化,調用方便。其接口的可維護性較佳,編譯時就可以發現接口兼容性問題,性能也非常不錯,十分適用于團隊內部的組件化場景。

最終我們選用了自研的prg::com作為跨端框架組件化的技術方案,下面具體介紹一下這個方案。

跨端組件化實踐

組件化方案,包含框架能力和組件約束兩部分。

框架設計是否科學,組件約束下是否易開發、易使用、易維護,是組件化方案要考量的核心因素。

  1. 組件框架,提供了組件運行的基礎能力,主要包括:組件發現機制組件生命管理組件間通信其他公共基礎能力
  2. 組件約束,定義了組件開發時需要遵循的標準,其主要目的包括了:支持組件在prg框架上運行,例如組件都繼承自prg::com對象,并需要完成I接口注冊。支持組件跨平臺,例如ui組件需要遵守mvp分層,在替換ui渲染層時,能確保做到業務邏輯多端一致。為了便于團隊協作,例如文件結構、代碼分層、命名規則等,使用相同范式去開發和使用組件。……

組件約束是根據組件的類型、具體使用場景等因素,分別進行定義的,不同組件的標準并不完全相同。

例如ui組件和非ui組件的標準就有很大的不同。

后面介紹下prg框架,及我們在各種場景下定義的組件約束條件。

?  prg框架

  • 組件發現機制

prg框架利用模板技術,通過打包時掃描dll生成配置、加載dll時靜態注冊組件,實現了一套組件發現機制。

prg框架的組件發現機制,依賴于id注冊,組件對外只暴露類id和I接口,實現了組件間完全去依賴。

先來看一下示意代碼:

// 定義一個prg::com組件
class IxxxService;
DEFINE_IID(IxxxService, "{4E6A382D-1FDA-49C6-8521-E284DA7B71CC}")
DEFINE_CLSID(xxxService, "{D1A52645-7587-4885-ABFD-323BA62905F5}")

// 創建這個prg::com組件
scoped_refptr<IxxxService> spInterface;
prg::PrgCOMCreateInstance(c_uuidof(xxxService), spInterface);

//////////////////////////////////////////////////////////////////////////
// implement(不對外暴露)
class CxxxService
: public prg::CPrgCOMRootObject<prg::CCOMThreadSafeRefPolicy>
, public IxxxService
{
public:
DECLARE_PRGCOM_RUNTIME(CxxxService, c_uuidof(xxxService), "xxxService", "xxxService", prg::GetDependsCLSID())

BEGIN_PRGCOM_MAP(CxxxService)
PRGCOM_INTERFACE_ENTRY(IxxxService)
END_PRGCOM_MAP()
}

IMPLEMENT_PRGCOM_RUNTIME(CxxxService);

它的實現原理是:

  1. 打包時,掃描目錄下所有dll,遍歷調用 GetPrgCOMFactory接口,生成組件配置xml。
  2. 創建對象時,通過xml配置,找到并load對應的dll。
  3. 加載dll時,會創建prg::CPrgCOMObjectRuntime<T>靜態變量g_prgRuntime,并在構造時向PrgCOMFactory注冊clsid到this的映射關系。
  4. 根據clsid,在PrgCOMFactory中找到對應的g_prgRuntime變量,調用CreateInstance靜態方法,由于g_prgRuntime變量是帶了T類型信息的,就可以創建出對應的T對象。

這里利用了c++模版技術和靜態注冊技術,巧妙地完成組件解耦,解決了依賴問題和跨模塊調用問題。

  • 組件生命管理

prg組件支持無感跨模塊創建、使用、釋放對象,真正做到了一次開發,到處使用,開箱即用。

prg組件使用scoped_refptr引用計數管理內存,使用者不需要自行管理內存。

prg框架支持跨dll/dylib創建、使用、釋放對象,對使用者來說dll/dylib是完全無感的,指定要創建的對象類型,接口類型,實例名稱,就可以直接開始使用這個接口了,非常絲滑。

class IxxxService : public prg::IPrgCOMRefCounted
{
public:
base::event<void()> onDataChanged;
public:
virtual bool GetData(const std::string& data) = 0;
}

// 創建prg::com組件新實例
scoped_refptr<IxxxService> spInterface;
prg::PrgCOMCreateInstance(c_uuidof(xxxService), spInterface);

// 獲取prg::com組件(沒有則create,prg框架內部會保存一份引用)
scoped_refptr<IxxxService> spInterface;
prg::PrgCOMGetInstance(c_uuidof(xxxService), instanceName, spInterface);

// 判斷prg::com組件實例是否存在
prg::PrgCOMHasInstance(c_uuidof(xxxService), instanceName, bhave);

// 刪除prg::com組件實例
prg::PrgCOMDropInstance(c_uuidof(xxxService), instanceName);

我們一般會將組件獲取封裝成像下面這樣的接口,對于使用者來說,調接口就像調用自己的代碼一樣方便。

/// 組件頭文件
inline scoped_refptr<IxxxService> GetIxxxService()
{
scoped_refptr<IxxxService> spInterface;
prg::PrgCOMGetInstance(c_uuidof(UIAppGuideWidget), "", spInterface);
return spInterface;
}

/////////////////////////////////////////////////////////////////////////
// 其他組件直接調用接口
std::string data;
GetIxxxService()->GetData(data);
  • 組件間通信

prg組件的接口調用和事件訂閱。

接口調用

prg組件接口調用與com組件類似,區別在于prg::com做了更好用的封裝,可以直接get到I接口對象進行使用。(當然還是支持使用QueryInterface,可以通過QueryInterface獲得不同類型的I接口)

class IxxxService : public prg::IPrgCOMRefCounted
{
public:
base::event<void()> onDataChanged;
public:
virtual bool GetData(const std::string& data) = 0;
}

// 獲取組件
scoped_refptr<IxxxService> spInterface;
prg::PrgCOMGetInstance(c_uuidof(xxxService), instanceName, spInterface);
// 調用組件方法
spInterface->GetData(callback);

事件訂閱

事件訂閱派發,依賴base::event實現,是典型的觀察者模式。當事件觸發時,按照注冊順序挨個調用觀察者的base::callback,可以非常容易的完成復雜流程串聯。這里的event是實例級別的,配合prg的賬號隔離能力,可以很好的解決多賬號業務的事件派發問題。但目前base::event暫不支持按優先級注冊派發。

class IxxxService : public prg::IPrgCOMRefCounted
{
public:
base::event<void()> onDataChanged;
public:
virtual bool GetData(const std::string& data) = 0;
}
// 獲取組件
scoped_refptr<IxxxService> spInterface;
prg::PrgCOMGetInstance(c_uuidof(xxxService), instanceName, spInterface);

// 訂閱組件事件
CBaseEventHelper::RegisterEvent(spInterface->onDataChanged, callback);

// 取消訂閱組件事件
CBaseEventHelper::UnRegisterEvent(spInterface->onDataChanged);

?  prg框架的組件約束

prg::com組件要遵循什么約束條件?

不同類型的組件,標準是不一樣的,要說組件標準,首先要對組件進行分類。

以阿里旺旺應用為例,跨端旺旺包含的組件,大致可以分成以下幾類:

框架層:

  1. ali系pc應用基礎組件
  2. 平臺相關基礎組件

框架和基礎組件,是阿里系pc應用基座,這些組件由prg框架內置,從而實現快速搭建pc跨端應用的能力。

應用層:

  1. 旺旺業務-非UI組
  2. 旺旺業務-UI組件

應用層組件,主要用來實現業務功能,這部分組件經常要進行擴展和修改,是我們要重點關注的。

應用層組件,根據其技術實現,又可以分成ui相關和ui無關兩種,ui組件會相對更加復雜。

(ps:UI組件上采用pv分層,p層負責控制界面邏輯,使用純c++實現,view層只負責繪制和操作輸入,這樣在最大程度復用代碼,提高效率的同時,保證業務雙端一致。我們的ui組件都遵從這個標準。我們選用了Qt作為跨端UI框架,我們發現,Qt并不能做到UI功能完全跨端,考慮到后續替換UI框架或適配新平臺的可能性,我們把Qt的使用范圍收斂在UI渲染部分,即view層。)

圖片

prg組件通用標準

prg::com組件基本標準,所有的prg組件都遵守。

每個prg組件,都以…Service命名,以 I…Service接口的方式對外暴露,在C…Service里實現。

Service概念:Service即是prgcom組件,是客戶端內的獨立業務單元,是對獨立業務能力的抽象。

接口:IxxxService(在biz/interface目錄,IxxxService.h文件)

實現:CxxxService(在biz/xxx/service目錄)

獲取實例:GetxxxService()

使用方法:

  1. 所有prg組件對外提供服務的方式是統一的。
  2. 使用者可以通過GetxxxService()接口獲取到prg組件實例,然后通過IxxxService提供接口和事件使用組件。
  3. 組件內部實現CxxxService不對外暴露。

圖片

非UI組件標準

不包含ui界面的組件,平臺差異影響較小,內部按業務需要設計,遵守prg組件基本標準即可。

  • UI組件標準

跨端ui組件的標準,主要包括了mvp分層,ui生命周期管理,以及各種場景下的多ui組合等。

ui組件依然遵從prg組件的通用標準,也支持prg組件的所有特性。

Service:是一個prgcom組件對象,外部使用ui組件時,直接操作service,就像使用非ui組件一樣

UI:是界面整體,ui里包含presenter、view, 這里ui和view要區分清楚。

Presenter:是界面的邏輯對象,p層控制了所有業務邏輯,也控制view的輸入輸出

View:是界面的渲染對象,只負責界面渲染和用戶操作輸入

在prg框架下,A組件調用組件B的UI接口:

圖片

ui組件的復雜性:

  1. 不同平臺下的ui機制不相同,界面風格和操作習慣也不同,如何確保雙端業務邏輯一致?
  2. ui對象的生命周期一般由ui框架內部管理,如何確保ui組件的生命周期管理不出問題?
  3. 如果一個組件里,包含多個ui怎么處理?多個ui之間并列關系怎么處理,嵌套關系又怎么處理?
  4. ui組件的場景太多,光標準定義就很復雜,如何在實際項目中落地實施?

mvp分層結構

為了更好的維護和復用ui組件,并滿足跨端訴求,我們的ui組件都采用mvp模式進行開發。

ui組件除了遵從prgcom的標準之外,還需遵守額外的約束:

  1. 每個UI界面內部,分為p-v兩層,其中p層負責邏輯控制,v層負責輸入輸出。
  2. 每個UI界面,開放一個IxxxUI接口,IxxxUI代表UI界面整體,內部只包含一個GetPresenter()方法。
  3. p層開放一個IxxxPresenter接口,外部調用IxxxPresenter提供的方法來操作這個UI界面。
  4. p層定義了v層需實現的輸入輸出接口IxxxUIDelegate,這個接口由v層代理實現,只在p層可見。
  5. v層只負責實現渲染和輸入用戶操作。

圖片

這種設計的好處,主要在于:

  1. 所有的邏輯由p定義和控制,p層由c++實現,可以實現跨多端,mac和windows統一。
  2. view被收斂在內部,僅實現了輸入輸出接口,非常輕量。view相關的對象(如QT對象)不會擴散。
  3. 替換view簡單,只需重新實現UIDelegate接口。
  4. 可以通過實現UIDelegate接口的mock,在p層做單元測試。

生命周期管理

ui組件的生命周期比一般組件復雜,因為ui組件有一部分對象的生命周期是ui框架來管理的。

買旺跨端框架,ui選型是Qt框架,ui對象生命周期由Qt內核管理,而組件生命周期是prg內核管理。

當創建ui對象后,組件保存了ui對象的指針,以便和ui對象做業務交互,但ui對象的生命周期是qt內部管理的。

因此,需要建立一種機制,當Qt銷毀ui對象的時候,需要通知到我們的組件這個ui對象已經被銷毀了。

創建和調用流程:

圖片

銷毀流程:

圖片

各種UI界面的處理

單個UI界面

圖片

多個平級UI界面

圖片

父子UI界面

圖片

多層UI界面嵌套下的接口調用

由于嵌套層級太多,每一層都要開接口傳遞,會帶來大量工作量,因此提供泛化接口傳遞的解決方案。

可參考案例IAliwangwangChatBase.h的實現,完成接口傳遞。

圖片

組件代碼自動生成?

跨平臺、標準化、低耦合,往往意味著編碼更加繁瑣,也意味著難以落地。

舉個例子,假如我在組件A要去操作組件B,顯示一個對話框,我需要寫的代碼有:

  1. IxxBService 組件接口
  2. CxxBService 組件實現
  3. IxxBPresenter P層接口
  4. CxxBPresenter p層實現
  5. IxxBPresenter::IxxBViewDelegate p層定義的ViewDelegate接口
  6. CxxBView view層實現

要在6個對象里寫代碼,這簡直就是一個災難!!!但是考慮到長期的可維護性、跨平臺,又必須這么做。

于是,我們開發了一個代碼生成工具,根據上面各種情況下的ui關系,可以從模板自動生成組件代碼。

由于篇幅限制,這里不具體展開。

?  產生的效果

這套跨端組件化方案,已在跨端千牛/跨端旺旺產品中落地,目前雙產品三端已經發布上線。

(目前win千牛功能 > 跨端千牛,跨端千牛的win版本尚未發布,敬請期待)

  1. 雙端完全一致的使用體驗,完全復用相同業務邏輯代碼。
  2. 雙端開發成本天然降低一半。
  3. 適合團隊協作,組件分拆,協同開發的效率高。
  4. 組件間完全解耦,可維護性大大增強。一次開發,到處使用,簡單方便。
  5. 可用工具自動生成組件代碼,只需關注業務邏輯,效率高,風格一致。
  6. 集成了大量集團基礎能力,沉淀了pc跨端應用組件化框架,提供快速搭建阿里系pc應用能力。

再回到我們選擇這個方案時的目標,

  1. 首先是支持跨平臺,
  2. 其次是可維護性、擴展性,長期來看,可維護性對產品質量、效能和研發體驗都影響深遠。
  3. 然后是良好的性能和穩定性,
  4. 最后是較好的研發效能和研發體驗。

目前來看,prg組件框架在前3點上表現出色,在第4點研發體驗上,由于跨多端的嚴苛要求,ui組件分層較多,開發略顯繁瑣,我們通過自研組件代碼生成工具,緩解了這一問題。

總的來說,prg組件跨端框架可以在未來的3-5年里,很好的支撐起千牛/旺旺,甚至其他阿里系pc應用的業務。

跨端組件框架的演進思考

?  技術基礎能力完善

框架基礎能力,例如支持事件訂閱優先級、支持組件鏈路/性能監控、增加基礎能力組件等。

ui組件單元測試能力,ui組件都是pv結構的,ui邏輯都在p層,用簡單的uidelegate即可串聯ui邏輯,實現ui單元測試。

研發效能和研發體驗,完善代碼模板和自動化工具 ,實現接口級別代碼自動生成/補全,進一步提升研發效率和研發體驗。

?  業務上可能的嘗試

走向業務的組件化

組件化不光是技術概念,也是業務概念。復用帶來了低成本和一致性,解耦則帶來了業務的靈活性。

組件在技術上的靈活復用,能帶來的是業務上的靈活組合,快速嘗試。

例如旺旺系的IM能力,它可以是獨立的阿里旺旺產品,也可以集成到千牛里。組件就是積木,更多從業務角度去思考,提供更多更好用的積木,業務就能快速搭建出一個新大樓。

  • 共享、共建pc組件庫

組件化不局限于團隊內,大家一起共享、共建的pc業務組件庫,才是更大程度發揮出組件化的價值。

希望pc業務越來越好!

團隊介紹

我們是大淘寶技術部行業與商家技術跨終端技術團隊,業務上負責為千萬級商家打造最高效的一站式工作臺千牛,為淘寶上億商家和消費者提供穩定高效的端到端消息IM服務;技術上深耕C++跨終端及PC桌面端技術(Windows&Mac),為商家,消費者提供穩定,可靠,高效的客戶端產品。


責任編輯:張燕妮 來源: 大淘寶技術
相關推薦

2014-05-26 16:52:29

移動前端web組件

2023-06-06 16:01:00

Web優化

2021-11-03 09:51:45

鴻蒙HarmonyOS應用

2012-08-24 09:34:58

戴爾

2023-02-01 18:33:44

得物商家客服

2019-10-25 10:42:51

框架Web開發

2017-07-24 13:58:49

Android組件化插件化

2011-09-07 14:20:42

Android Wid組件

2013-09-25 10:06:49

桌面虛擬化Persistent

2009-06-12 15:35:36

直播

2009-07-14 13:28:54

微軟虛擬化服務器虛擬化hyperv

2022-08-06 08:34:04

京東App適配技術棧

2009-03-04 10:27:50

客戶端組件桌面虛擬化Xendesktop

2025-03-14 00:53:12

2014-05-08 13:41:09

桌面虛擬化惠普

2022-05-20 11:09:15

Flybirds多端測試UI 自動化測試

2021-09-16 18:44:05

京東云PaaS平臺Android

2023-12-21 09:16:40

Electron前端多進程架構

2011-07-25 11:29:49

桌面虛擬化運營商

2011-07-08 09:11:34

惠普桌面虛擬化電信
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美高清性xxxxhd | 在线亚洲人成电影网站色www | 日韩在线不卡 | 亚洲精品aⅴ | 国产精品色| 伊人网91 | 欧美精品video | 亚洲三区在线观看 | 91麻豆精品一区二区三区 | 国产一级视频在线 | 国产精品成人一区二区三区夜夜夜 | 成人在线观看亚洲 | 91精品国产一区二区三区 | 四色永久 | 男女在线网站 | 久久伊人一区 | 国产在线观看一区二区三区 | 91精品久久久久久久久久入口 | 天天看片天天干 | 99精品国产一区二区青青牛奶 | 国产福利视频 | 奇米av | 毛片.com | 一区二区视频 | 羞羞视频一区二区 | 国产欧美在线一区 | av中文网 | 欧美日一区二区 | 国内精品视频一区二区三区 | 日本成人免费网站 | 精品毛片 | 中文字幕在线观看精品 | 在线免费观看视频你懂的 | 日韩精品视频中文字幕 | 欧美成人黄色小说 | 九色在线观看 | 玖玖精品视频 | 蜜月aⅴ免费一区二区三区 99re在线视频 | 一区二区高清 | 国产视频二区 | 精品综合|