摘要:但新增模塊的結構卻還是大致相同,此即是的經典設計模式這套模式也被開發者稱為三駕馬車。領域層定義負責表達業務概念,業務狀態信息以及業務規則。
本文首發于泊浮目的專欄:https://segmentfault.com/blog...前言
隨著ZStack的版本迭代,其可以掌管的資源也越來越多。但新增模塊的結構卻還是大致相同,此即是ZStack的經典設計模式——這套模式也被開發者稱為ZStack三駕馬車。
實例分析以PrimaryStorage為例,其APIMsg的真正邏輯處理第一站就是PrimaryStorageManagerImpl。
如果是對特定的PrimaryStorage進行操作,將會通過相應的Factory得出對應類型并轉發至相應的Base:
private void passThrough(PrimaryStorageMessage pmsg) { PrimaryStorageVO vo = dbf.findByUuid(pmsg.getPrimaryStorageUuid(), PrimaryStorageVO.class); if (vo == null && allowedMessageAfterSoftDeletion.contains(pmsg.getClass())) { PrimaryStorageEO eo = dbf.findByUuid(pmsg.getPrimaryStorageUuid(), PrimaryStorageEO.class); vo = ObjectUtils.newAndCopy(eo, PrimaryStorageVO.class); } Message msg = (Message) pmsg; if (vo == null) { String err = String.format("Cannot find primary storage[uuid:%s], it may have been deleted", pmsg.getPrimaryStorageUuid()); bus.replyErrorByMessageType(msg, errf.instantiateErrorCode(SysErrors.RESOURCE_NOT_FOUND, err)); return; } PrimaryStorageFactory factory = getPrimaryStorageFactory(PrimaryStorageType.valueOf(vo.getType())); PrimaryStorage ps = factory.getPrimaryStorage(vo); ps.handleMessage(msg); }
PrimaryStorageFactory是一個接口,在此基礎上有各式各樣的實現:如Local、Ceph、NFS等。
public interface PrimaryStorageFactory { PrimaryStorageType getPrimaryStorageType(); PrimaryStorageInventory createPrimaryStorage(PrimaryStorageVO vo, APIAddPrimaryStorageMsg msg); PrimaryStorage getPrimaryStorage(PrimaryStorageVO vo); PrimaryStorageInventory getInventory(String uuid); }
這就像現實中的模型一樣——在ZStack中可以有PrimaryStorage,而且可以有不同類型的PrimaryStorage:
PrimaryStorage:
Local
Ceph
NFS
這在軟件工程中即是一種分離領域(Layered Architecture)的具象。應用層對應ZStack的ManagerImpl,而Base更像是領域層。
應用層應用層的定義應該是:
定義軟件要完成的任務,并且指揮表達領域概念的對象來解決問題。這一層負責的工作對業務來說意義重大,也是與其他系統的應用層進行交互的必要渠道。
應用層要盡量簡單,不包含業務規則或者知識,而只為下一次的領域對象協調任務,分配工作,使它們互相協作。它沒有反映業務情況的狀態,但是卻可以具有另外一種狀態,為用戶或程序顯示某個任務的進度。
而在ZStack中,的確也像上面說的如此。在源碼中我們可以看到,對實例操作的API全部被轉發到了Base層去,而Manager這里handle的往往是一些過濾性、Get型API,如APIListPrimaryStorageMsg、APIGetPrimaryStorageMsg、APIGetPrimaryStorageTypesMsg等。
Manager即是API(這里API不僅僅是APIxxxMsg,同時包含用于通信的內部Msg。注意,它們都implements自Message這個接口)的入口,以及用于管理服務的生命周期。
領域層定義:
負責表達業務概念,業務狀態信息以及業務規則。盡管保存業務狀態的技術細節由基礎設施層(在ZStack如DataBaseFacade即是),但是反映業務情況的狀態是由本層控制并且使用的。注意,領域層是業務軟件的核心。
以PrimaryStorageBase為例,其本身對應了DB中的一條記錄,并且在改變狀態后也Refresh自己。并對操作多帶帶實例的Msg進行handle。
通信雖然分了層,并且關系是松散的。但是各個層之間也是需要通信的,那么層與層之間只能是單向的。上層可以直接使用或操作下層元素,方法是通過調用下層元素的公共接口,保持對下層元素的引用(至少是暫時的),以及采用常規的交互手段。而如果下層元素需要與上層元素通信,則需要采用另一種通信機制——比如回調或者Observers模式(在ZStack中即是ExtensionPoint)。
回調我們還是以PrimaryStorageBase為例。在其做鏈接操作時,邏輯如下:
private void doConnect(ConnectParam param, final Completion completion) { thdf.chainSubmit(new ChainTask(completion) { @Override public String getSyncSignature() { return String.format("reconnect-primary-storage-%s", self.getUuid()); } @Override public void run(SyncTaskChain chain) { changeStatus(PrimaryStorageStatus.Connecting); connectHook(param, new Completion(chain, completion) { @Override public void success() { self = dbf.reload(self); changeStatus(PrimaryStorageStatus.Connected); logger.debug(String.format("successfully connected primary storage[uuid:%s]", self.getUuid())); RecalculatePrimaryStorageCapacityMsg rmsg = new RecalculatePrimaryStorageCapacityMsg(); rmsg.setPrimaryStorageUuid(self.getUuid()); bus.makeLocalServiceId(rmsg, PrimaryStorageConstant.SERVICE_ID); bus.send(rmsg); tracker.track(self.getUuid()); completion.success(); chain.next(); } @Override public void fail(ErrorCode errorCode) { tracker.track(self.getUuid()); self = dbf.reload(self); changeStatus(PrimaryStorageStatus.Disconnected); logger.debug(String.format("failed to connect primary storage[uuid:%s], %s", self.getUuid(), errorCode)); completion.fail(errorCode); chain.next(); } }); } @Override public String getName() { return getSyncSignature(); } }); }
而不同的connectHook都有不同的實現。
在抽象等級上,PrimaryStorageBase是比圖中的這些Base高的。而這類具象Base可以Message返回Success或者Fail使高層Base做出不同的決策。
繼續,在PrimaryStorageBase中,其中handle APIAttachPrimaryStorageToClusterMsg的地方會做事件發送:
extpEmitter.preAttach(self, msg.getClusterUuid());
其會發送向:
在這里,一個Base通過了Observers模式向某個ManagerImpl發送了事件,實現了下層往上層的通信。
小結在大型軟件工程中,我們通常會給這樣的應用劃分層次。分別在每層中進行設計,使其具有內聚性并且只依賴于它的下層,而下層與上層也只有松散的耦合。這使得模型含義豐富,結構清晰。也使得整個應用架構更加茁壯。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68279.html
摘要:但在實際的二次開發中,這些做法未必能夠完全滿足需求。在源碼剖析之核心庫鑒賞一文中,我們了解到是的基礎設施之一,同時也允許通過顯示聲明的方式來聲明。同理,一些也可以使用繼承進行擴展。 本文首發于泊浮目的專欄:https://segmentfault.com/blog... 前言 在ZStack博文-5.通用插件系統中,官方提出了幾個較為經典的擴展方式。但在實際的二次開發中,這些做法未必...
摘要:源碼剖析之設計模式鑒賞策略模式小結在這篇文章中筆者和大家分享幾個減少的小由于這些都會有一定的限制因此還向大家介紹了幾個能夠避免寫出糟糕的的設計模式并使用觀察者模式簡單的改進了仲裁者模式的例子 本文首發于數據浮云:https://mp.weixin.qq.com/s?__... 在寫代碼的日常中,if...else語句是極為常見的.正因其常見性,很多同學在寫代碼的時候并不會去思考其在目...
摘要:能夠整體地替換算法,能讓我們輕松地以不同的算法去解決一個問題,這種模式就是模式。這個類是在發布前常在中被使用的一個類,代碼如下以為例,從語義上來說就是為了中的每個元素調用函數。 本文首發于泊浮目的專欄:https://segmentfault.com/blog... 前言 無論什么程序,其目的都是解決問題。而為了解決問題,我們又需要編寫特定的算法。使用Strategy模式可以整體地替...
摘要:本文首發于泊浮目的專欄在語言中,有一個關鍵字叫做其作用是在函數前執行。一般有兩種用法在該函數拋出異常時執行。在該函數返回前執行。這里的放入來自系統啟動時利用反射所做的一個行為。因此并不會影響使用時的性能。 本文首發于泊浮目的專欄:https://segmentfault.com/blog... 在Go語言中,有一個關鍵字叫做defer——其作用是在函數return前執行。在ZStac...
摘要:本文首發于泊浮目的專欄在語言中,有一個關鍵字叫做其作用是在函數前執行。一般有兩種用法在該函數拋出異常時執行。在該函數返回前執行。這里的放入來自系統啟動時利用反射所做的一個行為。因此并不會影響使用時的性能。 本文首發于泊浮目的專欄:https://segmentfault.com/blog... 在Go語言中,有一個關鍵字叫做defer——其作用是在函數return前執行。在ZStac...
閱讀 2323·2021-10-08 10:04
閱讀 1097·2021-09-03 10:40
閱讀 1150·2019-08-30 15:53
閱讀 3309·2019-08-30 13:13
閱讀 2925·2019-08-30 12:55
閱讀 2278·2019-08-29 13:21
閱讀 1330·2019-08-26 12:12
閱讀 2755·2019-08-26 10:37