Re: [J2SE] 談談Service的設計
※ 引述《sbrhsieh (十年一夢)》之銘言:
: : private static Map<Class<? extends IService>, IService> serviceMap = new
: : HashMap<Class<? extends IService>, IService>();
: : @SuppressWarnings("unchecked")
: : static public <T extends IService> T getService(Class<T> clazz) {
: : return (T)serviceMap.get(clazz);
: : }
: 我不明白第二點的意思。T被限制住一定是傳入的Class<T>,這與從 serviceMap 取出
: 一個 value 會是 T 的關聯是?
: compiler 會給 warning 就是因為它沒有辦法確定他所產生的 code 能夠保證
: 型別上的正確。
: getService method 宣稱它會傳回完全相容於參數所指定的型別的物件,而其實作
: 是從一個 Map 的 value 而來,依照 serviceMap 的 generics 宣告,只能確定 value
: 定是 IService 相容的物件(當然這裡不考慮使用 casting 亂搞的行為),getService
: 的實作中 compiler 所產生的 guarding code 是沒有辦法確定它一定能夠傳回相容於
: 參數所指定的型別,需要你要求 supress warning 並不是莫名其妙的事情。
: 編譯器沒有在 compile-time 做到型別上的保證,同樣地你也沒有辦法,你會覺得
: 你有信心還是在於你去 reasoning 你的程式流程,認定這樣子沒錯。如果這個
: serviceMap 不是完全由你掌控(比如它從別處而來或是它的 reference 可擴散到
: 其他地方),你就不會認為這個 SupressWarning 是沒有疑慮的,不是嗎?
恩...我大概懂你想表達的意思了,基本上你是對的,我著眼的地方跟你有點落差
我著眼在於"我認定這個是個black box(很有信心)",而你是著眼於整個面向
擴散的問題我有考慮到,所以基本上跟註冊有關的code都會被嚴格限制在private
這也是為什麼這個系統當初不會搞一個什麼RegisterService啥的
而是把Map跟register()嚴格的以private禁錮在BaseService的理由之一
這點你也正確地指出來了。
不過既然我們有"這個設計沒有擴散的問題 只是可能會有Scaling的問題"的共識的話
(下文您就是回覆關於Scaling的問題)
這部分我想應該我跟你意見是一致的,只是你覺得這設計會有其他面向的問題
這倒是一個我沒想過的insignt,謝謝你的指教
"getService()回傳值系統只能保證是個IService 我卻是逼他轉成T
(即使他是實作於IService),所以會有warning,而我只是很有信心的設計成他是對的"
這應該就是你所想要表達的概念
: : 這點其實我不太懂為什麼叫做暴露細節
: : 大多數來講Service都有自己獨特的功能,除非像是CRUDService而且僅僅被限制在CRUD
: : 我們來分兩部分來講,比方說你提到的以及CRUD,這種Service的特徵是
: : "我服務的介面完全相同,差別僅在於我處理的Bean(我們稱為Marsheled Bean)"
: :[略]
: : 再來看第二種Service
: : 這些Service只有部分method是每個Service都相同的
: : 但是各個Service有自己獨特的不同,那我們的目標就不是"透過interface操作"
: : 我們必須讓使用者看到service獨有的功能才能做事
: : 就有如我blog裡面提到的第一個NameCardService
: : 只有他有sort跟getDuplicated,其他Service都沒有
: : 這算是惡性的expose嗎?我還真的想不到不expose的方法 XD
: : 如果你說的是我們應該要有一個INameCardService的話,正好,我們現在的設計有
: 我認為 service(or plugin) 都是可以在 runtime 去抽換的,那麼 client 一定是
: 以 interface 去操作之,不可能在編譯期去知道 service 確切實作者(class)。
: 即便不考慮 runtime 抽換 service/plugin,client 要使用到 class name 來取用
: service 的做法,不論是在開發上還是架構設計上,已放棄了許多彈性。
: service 由 interface 來定義它的功能,每個 service 都是一個獨立的
: interface,不會有"多種 service 由一個 interface 定義共通部分,然後特定
: service 有的功能就直接將 service 視為特定 class",而是若 service B 比
: service A 多一項功能,就應該有一個 interface 是比 service A interface 多
: 一項功能的 interface 來定義 service B。(多個 service interface 彼此間可以
: 行成一組階層)
: 我提出這一點的目的是:依你的範例來說它是個很單純的(陽春),可是即便如此你
: 還是用到兩個 SupressWarning,這 OK,若你能夠驗證你的設計定不會出錯。
: 可是若考量其他的需求來改良你的設計,當它變得複雜了,你可能會發現利用參數
: 來 infer return type 的做法,變得不太容易寫,SupressWarning 越來越難避免
: 且 SupressWarning 會擴散,情況不再是只有你需要 SupressWarning 你確定它是
: 無害的,也許 service 的實作者都需要用到 SupressWarning,那麼你就要要求
: 他們也能夠保證他們的 code 的正確性,否則你當初希望 client 可以很簡單地
: 取用到有正確編譯期型別的目標就失去了。
: *利用 argument 來 infer return type 的做法不算罕見,是不多但我認為這是
: 因為能這樣用的場合很有限,要寫多這樣的設計又不用到 SupressWarning 更是少,
: 如果要求實作中所用到的 code(library, core classes)的實作也不使用
: SupressWarning 則更少。
: 在很單純的應用中的話,想要 client 在取用 service 可以有正確的編譯期型別,
: 為什麼不考慮由你來寫個 Services 這樣的 utility class 來給 client 使用。
: class Services {
: IServiceA getServiceA(...);
: IServiceB getServiceB(...);
: ...
: }
: 由你來提供這些 method 裡的 wrapper code。
: 或者是設計像 ServiceRegistry 這種東西,有註冊/取得各種 Service 介面的實作品
: 的 method,實際使用註冊部分的 code 由你來寫,也可以簡單做到你要的效果。
這跟設計哲學有關係。
如果我們可以讓使用者單單只要繼承一個class,接下來他就可以完全使用這些功能
這種把使用者當"設計上的傻瓜"的哲學,在我經驗裡面會省下很多維護上的麻煩
(類似於qttr1說的爽到你艱苦到我)
按照你的寫法的話,使用者或者我,必須去手動幫他們添加一個個的service
(我稱這種叫做hard-code registry),一定得有一個人做這件事情
而要是我們甚至只要提供一組jar,要人import,然後繼承某個class寫Service就能搞定
我覺得這是這組機制設計的目的
目前來講Service使用者"都"不需要Supress這個Warning
拿出來的class直接就是已經轉好的class
所以在這個scale目前還沒看到你說的問題(也許以後會有?我不敢說那麼肯定XD
但是這也是我要避免的目標 -- 我連使用者轉型都有疑慮了
還放warning出來要他們supress? 不可能)
我想說的是 logdown裡面用來舉例的是個嚴重簡化過的例子
他想表達的僅僅只是一個generic technique,而非一個完整的Service設計概念
是我Service設計概念中的一部分(我在回給您的回覆中有提到我們現行Service是
怎麼跑的,您可以清楚的看到Service因為某些理由,是有自己的獨立Interface
比方說我回覆給您的IMasterChannelService)
目前設計上是可以把IService/BaseService包成jar給使用者去跑,把這端一刀切成
Framework端,而使用者要做的是引入這個jar 繼承BaseService
然後寫自己的ISomeService
不過我想現在我不管怎麼講,應該都不夠清楚 =P
因為其實這篇該說的應該僅僅只是Generic Technique
關於Service的設計上,除了您給的demo code我沒辦法贊同以外
其實應該在大多數的想法上我跟你都是in the same page
不過您提到的SupressWarning方面的看法面向也是很重要,感謝指教
相信等我有空把真正的Service設計哲學提出大家分享的時候
應該會激起更多的水花 :)
另外有一點我比較困擾的是,很多code其實是以C++ policy based design寫出來的
要怎麼把他轉成java跟大家一起討論架構設計 其實對我已經是個很嚴苛的挑戰了(汗)
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 119.14.20.94
※ 編輯: Killercat 來自: 119.14.20.94 (07/21 16:53)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 9 之 9 篇):