<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          復(fù)雜系統(tǒng)設(shè)計(jì)原則與案例

          共 9957字,需瀏覽 20分鐘

           ·

          2023-08-23 05:47

          一、復(fù)雜是軟件的本質(zhì)屬性

          1.1 復(fù)雜是軟件的本質(zhì)屬性

                互聯(lián)網(wǎng)經(jīng)歷了十多年的高速發(fā)展,各個(gè)領(lǐng)域方向的系統(tǒng)都已經(jīng)歷了多次升級迭代,大家在經(jīng)手這些軟件系統(tǒng)時(shí),不免感嘆現(xiàn)在軟件系統(tǒng)的復(fù)雜度,其實(shí)件復(fù)雜性是軟件固有的屬性,這種固有的復(fù)雜性主要由4個(gè)方面的原因造成的:

          • 問題域的復(fù)雜性

          • 管理開發(fā)過程的復(fù)雜性

          • 隨處可變的靈活性

          • 描繪離散系統(tǒng)行為的問題

                 上面每一個(gè)方面都有極大的挑戰(zhàn),以「問題域的復(fù)雜性」為例,現(xiàn)以微服務(wù)架構(gòu)設(shè)計(jì)思路下的大型系統(tǒng)中,動(dòng)不動(dòng)就幾十個(gè)應(yīng)用,組合在一起就是一個(gè)復(fù)雜的系統(tǒng),而每個(gè)人只負(fù)責(zé)其中一小部分,想要了解系統(tǒng)全部的運(yùn)行狀況是很難的,哪怕一個(gè)子系統(tǒng),它包含的業(yè)務(wù)規(guī)則就巨多,因此說軟件復(fù)雜是它的本質(zhì)屬性。

          1.2 對業(yè)務(wù)認(rèn)知復(fù)雜度是影響軟件復(fù)雜性的重要因素

                  影響軟件復(fù)雜度的因素有很多,其中「認(rèn)知復(fù)雜度」占據(jù)著很重要的因素一提到復(fù)雜性,我們腦海里會(huì)浮出各種各樣的印象:應(yīng)用數(shù)多、代碼行數(shù)超過百萬級、業(yè)務(wù)規(guī)則復(fù)雜等,這些復(fù)雜度從本質(zhì)上來看是認(rèn)知復(fù)雜度超過了正常人的認(rèn)知范圍,比如看百萬行級的代碼與看100行代碼相比,維護(hù)10個(gè)應(yīng)用與維護(hù)1個(gè)應(yīng)用相比,兩個(gè)復(fù)雜度不是在同一個(gè)數(shù)量級上,有可能是指數(shù)級提升。認(rèn)知復(fù)雜度是軟件的本質(zhì)復(fù)雜度,從根本上規(guī)避不了,只能去理解、消化吸收,我們能做的是在理解的基礎(chǔ)上去發(fā)現(xiàn)共性的「規(guī)律」,將這些「規(guī)律」抽象出來,讓應(yīng)用層開發(fā)變得簡單。

                 舉當(dāng)前的例子,目前負(fù)責(zé)的是電商板塊的物流資金結(jié)算業(yè)務(wù)系統(tǒng),最開始面對的業(yè)務(wù)認(rèn)知復(fù)雜度非常高,它關(guān)聯(lián)電商交易、支付、營銷、結(jié)算、資金等領(lǐng)域,依賴業(yè)務(wù)將近100張離線表,除了要理解電商業(yè)務(wù)鏈路外,還要站在物流,財(cái)務(wù),風(fēng)控等視角把這些數(shù)據(jù)有序地組織起來,復(fù)雜度一下子就上升上來了,新人至少要花3個(gè)月的時(shí)間去消化這些業(yè)務(wù)知識。 當(dāng)進(jìn)來做了一些需求開發(fā)后,慢慢發(fā)現(xiàn)了一些規(guī)律,利用發(fā)現(xiàn)的這些規(guī)律有助于提升需求溝通、開發(fā)的效率。

          二、應(yīng)對復(fù)雜性的設(shè)計(jì)方法

          2.1 把握套路是應(yīng)對復(fù)雜性的根本方法

                「規(guī)律」是日常開發(fā)中發(fā)現(xiàn)有共性的地方,往后再遇到可以同樣的問題可加速解決的效率。軟件復(fù)雜度伴隨著軟件研發(fā)開始就產(chǎn)生的問題,「設(shè)計(jì)原則」就是應(yīng)對復(fù)雜性過程中總結(jié)出來的規(guī)律。常見的設(shè)計(jì)原則有SOLID、GRASP、KISS、分層等,這些設(shè)計(jì)原則指導(dǎo)我們在面對復(fù)雜系統(tǒng)時(shí)應(yīng)該如何去設(shè)計(jì)。原則的東西,個(gè)人經(jīng)驗(yàn)是建立自己的認(rèn)知體系,需要有實(shí)事求是,學(xué)以致用的實(shí)踐態(tài)度。

          6d5190a5a53d35afd69f2ced17bb2265.webp

          2.2 通識規(guī)律

                 在經(jīng)典的設(shè)計(jì)原則之上,最終將設(shè)計(jì)原則歸類成三個(gè)方面:「職責(zé)分解」、「層次抽象」和「變化擴(kuò)展」。

          2.2.1 職責(zé)分離

                   對職責(zé)分離有兩點(diǎn)體會(huì):一個(gè)是「你擁有什么信息就應(yīng)該承擔(dān)怎樣的職責(zé)」;另一個(gè)是「一個(gè)類只做一件事」。當(dāng)我們在討論是否是貧血模型時(shí),你可以用這個(gè)原則去檢驗(yàn),如果一類中的成員屬性操作放在另外一類中,大概率是不符合信息專家原則,舉一個(gè)簡單的例子,比如要計(jì)算物流訂單的運(yùn)費(fèi)金額,那么這個(gè)計(jì)算方法應(yīng)該是在訂單類中,而不是放在另外一個(gè)類中,因?yàn)橛唵晤愔杏杏唵蔚膯蝺r(jià)和數(shù)量。

                  另一點(diǎn)是出自于SOLID的單一職責(zé),它的原意是一個(gè)類只有一個(gè)變化的原因,一個(gè)類專注于做一件事的好處是可提升復(fù)用性和減少依賴,反之一個(gè)類耦合了不同的操作,修改的頻次就會(huì)變多,盡量少改動(dòng)穩(wěn)定的部分,在系統(tǒng)穩(wěn)定性中有一個(gè)共性認(rèn)知:故障的發(fā)生大概率與最近的發(fā)布有關(guān)。

                職責(zé)分解最大的挑戰(zhàn)是一個(gè)職責(zé)到底要?jiǎng)澐值蕉嗉?xì)或多粗,只能說只做一件事或者只有一個(gè)變化這樣大的指導(dǎo)原則,更多是我們在實(shí)踐中總結(jié)出來的經(jīng)驗(yàn),比如「變與不變分離」、「讀寫分離」、「配置域與執(zhí)行域分離」。

          2.2.2 層次抽象

                   層次抽象是利用已發(fā)現(xiàn)的規(guī)律,讓往后的開發(fā)變得簡單,當(dāng)我們在一線開發(fā)中,你會(huì)發(fā)現(xiàn)有一些規(guī)律,比如在日常開發(fā)中,發(fā)現(xiàn)開發(fā)主要涉及到與前端交互、業(yè)務(wù)邏輯處理和數(shù)據(jù)存儲(chǔ),這樣就可以分成三層:「視圖層」、「業(yè)務(wù)邏輯層」和「數(shù)據(jù)訪問層」。

                 高層次依賴低層次,最高層次越具象,也會(huì)越簡單,舉一個(gè)例子,在傳統(tǒng)Servlet開發(fā)中,一般的步驟是獲取參數(shù)信息并轉(zhuǎn)成業(yè)務(wù)層的對象,再進(jìn)行業(yè)務(wù)處理,雖然不同的業(yè)務(wù)處理邏輯是不一樣的,但參數(shù)獲取是具有共性的操作,在SpringMVC中,我們可以直接定義POJO去映射參數(shù),可以不用使用HttpServlet底層的操作去獲取參數(shù),這就是一種典型的層次抽象。

              「層次特性」是復(fù)雜系統(tǒng)的固有屬性,需要我們不斷去探索,分層的確能極大地降低認(rèn)知復(fù)雜度,相當(dāng)是站在巨人的肩膀上看問題,利用已發(fā)現(xiàn)的規(guī)律辦事效率會(huì)高很多,如上文提到的財(cái)務(wù)核算,做多了就會(huì)發(fā)現(xiàn)就那幾種模式,當(dāng)你沒有摸清里面的規(guī)律時(shí),會(huì)覺得顯得很零散。

          2.2.3 變化擴(kuò)展

                  軟件如果沒有變化,也就不需要所謂的設(shè)計(jì)原則,一次性工程怎么快就怎么來,而現(xiàn)實(shí)中遇到最多的現(xiàn)象是需求不斷變化。變化擴(kuò)展的挑戰(zhàn)不在于技術(shù),而是在于「怎么認(rèn)知到哪里有變化」。常見變化擴(kuò)展的技術(shù)有:配置項(xiàng)、接口、抽象類、攔截器、SPI、插件等,這些都是具體的解決手段,它們并不復(fù)雜,復(fù)雜在于哪里會(huì)有變化,這個(gè)是最難的。

                 認(rèn)識到多少變化,它取決于認(rèn)識的寬度,看到多少內(nèi)容會(huì)影響到系統(tǒng)設(shè)計(jì),比如在SpringMVC中,我們最高常操作的是定義一個(gè)Controller,再在方法上寫一個(gè)RequestMapping注解,但在實(shí)際中,它還有另外的寫法,如實(shí)現(xiàn)Controller接口,正是有不同的場景和類型,處理上還有差別,此時(shí)就會(huì)有變化擴(kuò)展的訴求。

          2.3 軟件設(shè)計(jì)的6條經(jīng)驗(yàn)

                  在經(jīng)典的設(shè)計(jì)原則之上,結(jié)合實(shí)踐過程中的得與失,總結(jié)了以下6條設(shè)計(jì)經(jīng)驗(yàn),為了更容易理解,下面的案例選用常用的開源框架剖析設(shè)計(jì)思想,方便與大家產(chǎn)生共鳴。

          2.3.1 模板方法-在多變中找不變

                  當(dāng)一個(gè)業(yè)務(wù)有多個(gè)場景,并且不同的場景處理既有共性的地方,也有差異性的地方時(shí),此時(shí)最容易想到的方法是用「模板方法」固定共性的邏輯,差異性的邏輯放到子類中實(shí)現(xiàn)。在開源框架中,我們經(jīng)常見到這樣的設(shè)計(jì)思想,比如在SpringMVC中查找Handler的過程,不同的場景查找邏輯不一樣,最常見的是RequestMapping方式查找,它是在HandMapping接口類中定義getHandler方法。

              
                public interface HandlerMapping {

          HandlerExecutionChain getHandler(HttpServletRequest request)

                  throws Exception;

          }

                然后在抽象類AbstractHandlerMapping中定義模板方法,抽象方法又交由子類去實(shí)現(xiàn)。

              

          public final HandlerExecutionChain getHandler(HttpServletRequest request)

          throws Exception {

          // 抽象方法,交由具體的子類實(shí)現(xiàn)
          Object handler = getHandlerInternal(request);
          if (handler == null) {
          handler = getDefaultHandler();
          }
          if (handler == null) {
          return null;
          }

          // 省略部分代碼
          HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

          // 省略部分代碼
          return executionChain;
          }

                  在MyBatis框架中,Executor定義了增刪改查等方法,具體實(shí)現(xiàn)有如單條命令執(zhí)行、批量命令執(zhí)行等,模板方法定義在BaseExecutor類中,類結(jié)構(gòu)繼承關(guān)系如下所示,這也是一種最簡單的三層設(shè)計(jì)結(jié)構(gòu):接口類、抽象類、子類。

          9f239655990802ab933a5cbe96d9081f.webp

          2.3.2 命令職責(zé)-業(yè)務(wù)鏈路查詢和復(fù)雜組裝

                  有一類業(yè)務(wù),它涉及「查詢」與「組裝」兩個(gè)操作,比如Spring中有Bean查詢操作,與之對應(yīng)的有Bean創(chuàng)建操作,這兩個(gè)職責(zé)是不一樣的,也有的稱之為「讀寫分離」或者「查詢與命令分離」,從本質(zhì)上講,它也遵循了接口單一職責(zé)。

          4dfe8420cd8fd8100416c3acf162c671.webp

          2.3.3 配置域與執(zhí)行域分離-有面向用戶配置

                 有些業(yè)務(wù)前臺(tái)用戶能夠直接配置操作的,比如在SpringMVC中,我們配置一個(gè)Controller的請求可以配置不同的屬性,其中RequestMapping是直接面向用戶視角的配置操作,在配置域的內(nèi)容,是與現(xiàn)實(shí)操作一一映射的,RequestMapping對應(yīng)有一個(gè)類叫RequestMappingInfo,然而在執(zhí)行域,此時(shí)它就不需要配置域中的那么多信息,執(zhí)行過程只要對象和方法的信息即可,對應(yīng)有一個(gè)類中HandlerMethod,由此可見,配置域和執(zhí)行域兩個(gè)抽象的視角是不一樣的,一個(gè)是現(xiàn)實(shí)世界的直接映射,一個(gè)是偏底層執(zhí)行。

              @RestController
          public class UserController {

          @RequestMapping(value = "/acquire", method = RequestMethod.GET)
          public User getUser(@RequestParam("name") String name, @RequestParam("age") Integer age) {

          return null;
          }
          }

          RequestMappingHandlerMapping類結(jié)構(gòu)繼承關(guān)系如下圖所示。

          c2bfa793a496dea38fbadee375136e8e.webp

                  再比如在Spring中,允許用戶配置自定義的編輯器、BeanPostProcessor處理器,也是由一個(gè)單獨(dú)的接口類ConfigurableBeanFactory表達(dá)的。a01fd40d490cf917d7a001e49de50a4e.webp

                 這樣的例子還有很多,比如BeanDefinition是面向配置域的,Bean是執(zhí)行域的,我們在定義Bean有很多的屬性,這些屬性信息在BeanDefinition類中定義,而在執(zhí)行過程中會(huì)生成一個(gè)對象,本質(zhì)上是一個(gè)Object。

          2.3.4 封裝變化-業(yè)務(wù)有多樣變化

                應(yīng)對變化的方法有很多,難的是要感知到變化并且封裝好變化,比如Spring Bean實(shí)例化后進(jìn)行初始化,在此期間就有很多操作,如常見的Bean依賴注入、AOP代理等,Spring抽象出BeanPostProcessor擴(kuò)展類,在Bean初始化前后做一些額外的擴(kuò)展工作。

              public interface BeanPostProcessor {
          // 初始化前的操作
          Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
          return bean;
          }

          // 初始化后的操作
          Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          return bean;
          }
          }

                 設(shè)計(jì)擴(kuò)展點(diǎn)時(shí)一定要把握好度,粒度過細(xì)則擴(kuò)展點(diǎn)數(shù)量非常多,在Spring中設(shè)計(jì)就比較好,對于開發(fā)而言,有兩個(gè)時(shí)機(jī)有明顯的擴(kuò)展訴求,一個(gè)是在Bean掃描時(shí),可以允許用戶自定義Bean,此時(shí)有BeanFactoryPostProcessor擴(kuò)展接口;另一個(gè)是在Bean初始化時(shí)的擴(kuò)展,對應(yīng)有BeanPostProcessor擴(kuò)展接口。不管是Spring內(nèi)部使用,還是外部開發(fā),都是使用同樣的擴(kuò)展。

          2.3.5 責(zé)任鏈-業(yè)務(wù)流程型操作

                  業(yè)務(wù)型操作,有明顯的流程痕跡,比如前置檢查、協(xié)議組裝、接口調(diào)用等,節(jié)點(diǎn)與節(jié)點(diǎn)之間就構(gòu)成了一條鏈條,只不過平時(shí)寫代碼時(shí)我們是放在一個(gè)大的流程中實(shí)現(xiàn)的。在HttpClient中,對于請求,我們有不同的操作流程,比如重試、緩存、重定向、調(diào)用socket等操作,HttpClient使用責(zé)任鏈的模式。

          8cf25c1840c7a8c309344ac205cd459f.webp

                  鏈條上的每個(gè)節(jié)點(diǎn)都是獨(dú)立操作的,方便擴(kuò)展,責(zé)任鏈核心是鏈的構(gòu)建和節(jié)點(diǎn)設(shè)計(jì),這給平時(shí)寫流程型業(yè)務(wù)代碼提供了一種新的思路,大型系統(tǒng)中,有流程引擎,本質(zhì)來講它也是一條鏈,一個(gè)節(jié)點(diǎn)做完之后下一個(gè)節(jié)點(diǎn)繼續(xù)做,思想上大同小異。

          2.3.6 合理抽象-復(fù)雜系統(tǒng)場景

                 抽象是應(yīng)對復(fù)雜場景的重要方法,這一點(diǎn)我們并不懷疑,最難的是要抽象什么去刻畫業(yè)務(wù),比如AOP切面編程,站在用戶視角,就是告訴他哪些類、哪些方法需要被增強(qiáng)什么共性業(yè)務(wù)邏輯,比如日志切面類、權(quán)限切面類等,AOP對它的抽象是「對指定的類和方法以某種方式織入特定的共性邏輯」。其中指定的類和方法抽象成切點(diǎn),以某種方式抽象成通知。此時(shí),你會(huì)發(fā)現(xiàn)它抽象出了一些概念出來,如切面、切點(diǎn)、通知。因此,對復(fù)雜業(yè)務(wù)場景,一定要有一套抽象的元數(shù)據(jù)去表征它,也即是領(lǐng)域模型,最高明的建模方法是下定義的方法,用一句簡明的話講清楚業(yè)務(wù)的結(jié)構(gòu)和功能。

          67ac2fa97f22d9b3f6ae5f106b0f78b6.webp

                  系統(tǒng)是元素和元素間以某種關(guān)聯(lián)關(guān)系構(gòu)成的一種結(jié)構(gòu),復(fù)雜系統(tǒng)是構(gòu)成元素更多、關(guān)聯(lián)關(guān)系更復(fù)雜,核心還是要找到「結(jié)構(gòu)」,這種結(jié)構(gòu)也即是領(lǐng)域模型,好的領(lǐng)域模型可遇而不可求,是要花大量的時(shí)間去探尋它,突然有一天在你腦海里靈光一現(xiàn)就出來了,這種感覺很奇妙,因此,領(lǐng)域建模是非常依賴經(jīng)驗(yàn)而非方法。

          三、框架設(shè)計(jì)案例分析

                  有了上面的分析基礎(chǔ),再以SpringMVC DispatcherServlet為例,分析它的設(shè)計(jì)思想,它的結(jié)構(gòu)如下圖所示。

          292939a6b520f943f2effa281f5bd63f.webp

                  SpringMVC核心是對HttpServlet的封裝,在HttpServlet中有兩個(gè)重要的方法,一個(gè)是init()方法,一個(gè)是service()方法,init()方法是Servlet初始化時(shí)回調(diào)的方法,service()是處理請求時(shí)回調(diào)的方法。

                  在HttpServletBean類中,它重寫了HttpServlet init()方法,主要完成SpringMVC子容器初始化的過程。FrameworkServlet類主要重寫了service()方法,處理實(shí)際的如GET、POST請求,但它只是定義了一個(gè)抽象的doService()方法,實(shí)際處理過程是在DispatcherServlet類中,分發(fā)的Servlet是攔截所有的請求,然后匹配到目標(biāo)Handler執(zhí)行。

                 在DispatcherServlet類的設(shè)計(jì)中,體現(xiàn)出了「職責(zé)分離」和「變化擴(kuò)展」的設(shè)計(jì)思想,init初始化與service執(zhí)行分離,攔截器支持變化擴(kuò)展。上面列舉的幾個(gè)框架,它們都是解決了一些平常的問題,但不影響它們優(yōu)秀的設(shè)計(jì),如MyBatis、Spring、SpringMVC、HttpClient,它們并沒有在一個(gè)大類中實(shí)現(xiàn)各種各樣的功能,而是切分放在不同的類中,并且通過多層繼承關(guān)系組合在一起,不管是可讀性上,還是可擴(kuò)展性上都非常不錯(cuò)。

          四、認(rèn)知是解決復(fù)雜性的基石

                  在認(rèn)知面前,所有的方法和工具都是蒼白的,就像一個(gè)人想不勞而獲一樣,總想找一種萬能的方法解決所有的問題,而事實(shí)并沒有,還得靠在實(shí)踐中解決問題。復(fù)雜性也是同樣的問題,沒有萬能的方法解決它,只有原則作為指導(dǎo),而具體要怎么去做,還是得身體力行。當(dāng)我們不理解框架為什么要設(shè)計(jì)得這么復(fù)雜時(shí),大概率是我們對應(yīng)用的場景了解還不夠全面。

          4.1 業(yè)務(wù)認(rèn)知

                  當(dāng)大家第一次去看Spring Bean掃描的邏輯時(shí),它的邏輯是很復(fù)雜的,如果讓我們自己去實(shí)現(xiàn)一個(gè),你可能會(huì)很簡單的設(shè)計(jì)出來,根據(jù)指定的路徑掃描所有的類,如果有@Component的注解時(shí)就存放到BeanDefinnitionMap中,那為什么Spring要設(shè)計(jì)得這么復(fù)雜呢,原因是現(xiàn)實(shí)場景中Bean定義有多種方法,比如嵌套定義Bean,再比如先掃描出一部分Bean,此時(shí)這些Bean中有定義@CompentScan,又可以加載其它的Bean,所以你看這么多你不曾考慮的場景疊加在一起,實(shí)現(xiàn)起來的復(fù)雜度自然就高了。

                  還比如SpringMVC在查找Handler時(shí),它的邏輯也挺復(fù)雜的,與我們?nèi)粘Mㄟ^一個(gè)URL映射到一個(gè)Handler不一樣,在現(xiàn)實(shí)中完全有一種可能是相同的URL對應(yīng)不同的請求方法,此時(shí)就不是一個(gè)簡單映射的就能完成,還有一大堆的匹配邏輯,所以你會(huì)看到,當(dāng)我們的業(yè)務(wù)認(rèn)知了解得越來越多時(shí),在設(shè)計(jì)中就會(huì)考慮更多的因素。

                  提升業(yè)務(wù)認(rèn)知,除了溝通交流外,還得踏踏實(shí)實(shí)去工作一段時(shí)間,真正地了解里面的問題是什么,即使是踩坑,也是修正自己的認(rèn)知。

          4.2 技術(shù)認(rèn)知

                   除了業(yè)務(wù)認(rèn)知外,技術(shù)也是在不斷發(fā)展的,如果你不了解某個(gè)技術(shù)或技術(shù)點(diǎn),此時(shí)你也不會(huì)想到好的設(shè)計(jì)方法。比如讓你設(shè)計(jì)一個(gè)事件通知框架,本來這個(gè)功能倒不是那么復(fù)雜,它最難的點(diǎn)是在于如何找到事件對應(yīng)的事件處理器,此時(shí)就有不同的解決方案,一種最簡單的方法是在定義事件處理器時(shí)讓用戶指定事件類型,這似乎是一種解決方案,但站在用戶使用的角度看,它并不是一種好的解決方案,把復(fù)雜留給用戶而不是自己。為了提升用戶使用體驗(yàn),這里就要使用到泛型類型解析的方面的知識了,核心代碼如下:

              /**
          * 事件分發(fā)器
          *
          * @author fulai.gfl
          */
          public class EventDispatcher {

          /**
          * 事件列表
          */
          private static List<Event> events = new ArrayList<>();

          /**
          * 事件處理器列表
          */
          private static List<Handler> handlers = new ArrayList<>();

          /**
          * 添加事件
          */
          public static void addEvent(Event event) {
          events.add(event);
          }

          /**
          * 添加事件處理器
          */
          public static void addHandler(Handler handler) {
          handlers.add(handler);
          }

          /**
          * 觸發(fā)事件
          */
          public Object fire(Event event) throws Exception {

          Handler handler = getHandler(event);
          if(Objects.isNull(handler)){
          throw new Exception("event_name =" + event.getEventName());
          }

          return handler.handle(event);
          }

          /**
          * 根據(jù)事件找到對應(yīng)的Handler
          */
          private Handler getHandler(Event event) throws Exception {

          Handler handler = null;
          for (Handler h : handlers) {

          Type[] argumentsTypes =

                      ((ParameterizedTypeImpl)h.getClass()

                          .getGenericInterfaces()[0])

          .getActualTypeArguments();

          if (Class.forName(((Class)argumentsTypes[0])

                          .getName()).equals(event.getClass())) {

          handler = h;
          }

          }

          return handler;
          }
          }

          五、小結(jié)

                  本文主要講述了應(yīng)對復(fù)雜性的一些原則和經(jīng)驗(yàn),通過實(shí)際案例解構(gòu)設(shè)計(jì)思想,個(gè)人認(rèn)為好的設(shè)計(jì)是體現(xiàn)在「職責(zé)分離」、「抽象分層」和「變化擴(kuò)展」上,在類的結(jié)構(gòu)設(shè)計(jì)上尤其要花心思去想,如「變與不變分離」、「配置域與執(zhí)行域分離」、「查詢與命令分離」。歸根到底,認(rèn)知是解決復(fù)雜性的基石,如果要更好地發(fā)揮技術(shù)的作用,對業(yè)務(wù)的理解需要更好的認(rèn)識。






          瀏覽 38
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一区二区三区在线视频免费 | 色婷婷一区二区三区久久午夜成人 | 黄片在线视频 | 97青娱乐在线观看视频网站 | 欧美成人网站在线观看视频 |