日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
【分享】我在阿里工作十年里接觸過的Java框架設(shè)計(jì)模式

 一、前言

說起來設(shè)計(jì)模式,大家應(yīng)該都耳熟能詳,設(shè)計(jì)模式代表了軟件設(shè)計(jì)的最佳實(shí)踐,是經(jīng)過不斷總結(jié)提煉出來的代碼設(shè)計(jì)經(jīng)驗(yàn)的分類總結(jié),這些模式或者可以簡化代碼,或者可以是代碼邏輯開起來清晰,或者對(duì)功能擴(kuò)展很方便…

設(shè)計(jì)模式按照使用場景可以分為三大類:創(chuàng)建型模式(Creational Patterns)、結(jié)構(gòu)型模式(Structural Patterns)、行為型模式(Behavioral Patterns)。

  • 創(chuàng)建型模式(Creational Patterns)

    對(duì)對(duì)象的實(shí)例化過程進(jìn)行抽象,這使得一個(gè)系統(tǒng)可以不用關(guān)心這些對(duì)象是如何創(chuàng)建,組合,呈現(xiàn)的,對(duì)于類創(chuàng)建模式來說通過使用繼承改變實(shí)例化的類,對(duì)于對(duì)象創(chuàng)建模式來說通過使用代理來實(shí)例化所需要的對(duì)象。

  • 結(jié)構(gòu)型模式(Structural Patterns)

    通過對(duì)多個(gè)類和對(duì)象進(jìn)行組合得到復(fù)雜結(jié)構(gòu)的類,一般使用繼承繼承或者成員變量引用形式來實(shí)現(xiàn)。

  • 行為型模式(Behavioral Patterns)

    行為模式不僅表達(dá)了對(duì)象和類,還表達(dá)了他們之間的交互,涉及到了對(duì)象和算法的分配。

下面就帶大家看下開源框架框架中是如何應(yīng)用這些經(jīng)典設(shè)計(jì)模式的。

二、責(zé)任鏈設(shè)計(jì)模式(Chain of Responsibility Pattern)

2.1 介紹

責(zé)任鏈模式是把多個(gè)對(duì)象串聯(lián)起來形成一個(gè)鏈狀結(jié)構(gòu),讓每個(gè)對(duì)象都有機(jī)會(huì)對(duì)事件發(fā)送者的請(qǐng)求進(jìn)行處理。責(zé)任鏈模式是設(shè)計(jì)模式中的行為模式,設(shè)計(jì)意圖是為了使事件發(fā)送者和事件接受者之間解耦。通常責(zé)任鏈鏈中的每個(gè)對(duì)象都有下一個(gè)對(duì)象的引入(例如tomcat 里面StandardPipeline用來管理valve),或者有個(gè)同一個(gè)鏈管理工廠里面使用數(shù)組存放了所有的對(duì)象(例如tomcat里面ApplicationFilterChain用來關(guān)系filter)。

2.2 Tomcat中Valve鏈

Tomcat中StandardEngine,StandardHost,StandardContext里面都有自己StandardPipeline,下面以StandardEngine里面StandardPipeline為例講解

從上面類圖可知道每個(gè)Valve都要繼承ValveBase類,該類里面有一個(gè)Valve的引用,實(shí)際是鏈中下一個(gè)節(jié)點(diǎn)對(duì)象,Valve就是通過每個(gè)Valve里面的next串聯(lián)為鏈的。

每個(gè)valve的invoke方法里面調(diào)用next.invoke激活鏈中下一個(gè)節(jié)點(diǎn),并且StandardEngine,StandardHost,StandardContext都有一個(gè)basic valve這個(gè)valve在鏈的末尾用來激活子容器的valve鏈。

2.3 Tomcat中Filter鏈

Tomcat中Filter鏈?zhǔn)鞘褂肁pplicationFilterChain來管理的,具體結(jié)構(gòu)如下圖:

可知Filter鏈不是像Valve一樣在內(nèi)部維護(hù)下個(gè)節(jié)點(diǎn)的引用,而是在ApplicationFilterChain中搞了個(gè)數(shù)組存放所有的Filter,并通過n統(tǒng)計(jì)Filter總個(gè)數(shù),pos是當(dāng)前filter的下標(biāo)。

ApplicationFilterChain的doFilter代碼如下:

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { ... internalDoFilter(request,response); ... }private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Call the next filter if there is one if (pos < n) { //獲取filter鏈中下標(biāo)為pos的filter ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = null; try { filter = filterConfig.getFilter(); support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, filter, request, response); if (request.isAsyncSupported() && "false".equalsIgnoreCase( filterConfig.getFilterDef().getAsyncSupported())) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } ... //調(diào)用自定義filter的dofilter方法 filter.doFilter(request, response, this); support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, filter, request, response); } .... } .....}

2.4 使用場景

  • 當(dāng)一個(gè)請(qǐng)求需要根據(jù)請(qǐng)求參數(shù)的不同由不同對(duì)象來處理時(shí)候。

  • 當(dāng)一個(gè)請(qǐng)求需要固定對(duì)象順序處理,并且可擴(kuò)展性的在固定順序里面插入新的對(duì)象進(jìn)行處理時(shí)候。

三、工廠模式(Factory Pattern)

3.1 介紹

工廠模式是創(chuàng)建型模式,他封裝了對(duì)象的創(chuàng)建過程,調(diào)用者使用具體的工廠方法根據(jù)參數(shù)就可以獲取對(duì)應(yīng)的對(duì)象。

3.2 Spring框架中BeanFactory

如圖BeanFactory接口提供了getBean方法,在AbstractBeanFactory中實(shí)現(xiàn)了該方法,經(jīng)過層層繼承,實(shí)現(xiàn),最后DefaultListableBeanFactory實(shí)現(xiàn)了BeanDefinitionRegistry接口用來保存bean定義,繼承了AbstractAutowireCapableBeanFactory用來支撐autowired。

一個(gè)例子

@Testpublic void testBeanFactoy() throws NamingException, SQLException, ParseException, IOException { //創(chuàng)建Bean工廠 DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); //給bean工廠添加bean定義,解析xml里面的bean放入bean工廠 loadBeanDefinitions(bf); //根據(jù)名字從bean工廠獲取bean Hello hello = (Hello) bf.getBean("hello"); hello.sayHello(); Hello2 hello2 = (Hello2) bf.getBean("hello2"); hello2.sayHello();}protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); String[] configLocations = new String[] { "beans2.xml" }; if (configLocations != null) { beanDefinitionReader.loadBeanDefinitions(configLocations); }}

3.3 使用場景

  • 不同條件下創(chuàng)建不同實(shí)例,用于統(tǒng)一管理bean

  • 不同條件下調(diào)用不同工廠方法獲取不同場景下的bean

四、單例設(shè)計(jì)模式(Singleton Pattern)

4.1 介紹

單例模式是一種創(chuàng)建型模式,單例模式提供一個(gè)創(chuàng)建對(duì)象的接口,但是多次調(diào)用該接口返回的是同一個(gè)實(shí)例的引用,目的是為了保證只有一個(gè)實(shí)例,并且提供一個(gè)訪問這個(gè)實(shí)例的統(tǒng)一接口。

4.2 Spring中單例bean的創(chuàng)建

Spring中默認(rèn)配置的bean的scope為singleton,也就是單例作用域。那么看看它是如何做到的。

在AbstractBeanFactory類里面的doGetBean方法:

protected Object doGetBean( final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean = null; // 解決set循環(huán)依賴 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ... } else { ... // 創(chuàng)建單件bean. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory() { public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { ... throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //創(chuàng)建原型bean else if (mbd.isPrototype()) { ... } //創(chuàng)建request作用域bean else { ... } } ... return bean;}

getSingleton代碼:

public Object getSingleton(String beanName, ObjectFactory singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { ... beforeSingletonCreation(beanName); ... try { singletonObject = singletonFactory.getObject(); } catch (BeanCreationException ex) { ... } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); }}protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); }}private final Map singletonObjects = CollectionFactory.createConcurrentMapIfPossible(16);

可知Spring內(nèi)部是通過一個(gè)ConcurrentMap來管理單件bean的。獲取bean時(shí)候會(huì)先看看singletonObjects中是否有,有則直接返回,沒有則創(chuàng)建后放入。

看個(gè)時(shí)序圖:

Spring的bean工廠管理的單例模式管理的是多個(gè)bean實(shí)例的單例,是工廠模式管理所有的bean,而每個(gè)bean的創(chuàng)建又使用了單例模式。

4.4 使用場景

  • 同一個(gè)jvm應(yīng)用的不同模塊需要使用同一個(gè)對(duì)象實(shí)例進(jìn)行信息共享。

  • 需要同一個(gè)實(shí)例來生成全局統(tǒng)一的序列號(hào)。

五、原型設(shè)計(jì)模式(Prototype Pattern)

5.1 介紹

相比單例設(shè)計(jì)模式,原型模式是每次創(chuàng)建一個(gè)對(duì)象,下面看下spring是如何使用原型模式的。

5.2 Spring中原型bean的創(chuàng)建

創(chuàng)建原型bean需要在xml特別說明:

protected  T doGetBean( final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { ... } else { ... try { ... // Create bean instance. if (mbd.isSingleton()) { ... } //創(chuàng)建原型bean else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { ... } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } }... return (T) bean;}

createBean函數(shù)里面則是根據(jù)bean定義創(chuàng)建新bean,感興趣的可以看看。

5.3 使用場景

  • 當(dāng)有業(yè)務(wù)場景使用某個(gè)bean時(shí)候需要使用自己的一個(gè)拷貝的時(shí)候使用。

六、 策略模式(Strategy Pattern)

6.1 介紹

策略模式屬于行為性模式,它定義一系列的算法對(duì)象,使用時(shí)候可以使它們相互替換。

6.2 Spring中bean實(shí)例化策略

首先看下類圖:

從圖知道:接口InstantiationStrategy是實(shí)例化策略接口類,它定義了三個(gè)實(shí)例化接口,然后SimpleInstantiationStrategy實(shí)現(xiàn)了該策略,它主要做一些簡單的根據(jù)構(gòu)造函數(shù)實(shí)例號(hào)bean的工作,然后CglibSubclassingInstantiationStrategy又繼承了SimpleInstantiationStrategy新增了方法注入方式根據(jù)cglib生成代理類實(shí)例化方法。

在AbstractAutowireCapableBeanFactory中管理了該策略的一個(gè)對(duì)象,默認(rèn)是CglibSubclassingInstantiationStrategy策略,運(yùn)行時(shí)候可以通過setInstantiationStrategy改變實(shí)例化策略,如果你自己寫個(gè)策略的話。

6.3 Spring中Aop代理策略

首先看AopProxyFactory接口類提供了createAopProxy接口,這個(gè)是策略模式的接口方法。然后DefaultAopProxyFactory實(shí)現(xiàn)了該接口作為策略的實(shí)現(xiàn)者。然后ProxyCreatorSupport里面引用了AopProxyFactory,并且提供了get,set方法用來運(yùn)行時(shí)改變策略,這里Spring只實(shí)現(xiàn)了DefaultAopProxyFactory這一個(gè)策略,如果需要自己也可以寫個(gè)。

DefaultAopProxyFactory里面的createAopProxy的邏輯如下,可以在運(yùn)行時(shí)根據(jù)參數(shù)決定用Cglib策略還是JDK動(dòng)態(tài)代理策略生成代理類:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { //如果XML打開了優(yōu)化開關(guān),或者設(shè)置為了代理目標(biāo)類,或者目前類沒有接口 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } //如果有接口,或者通過Proxy.newProxyInstance生成的,則使用jdk動(dòng)態(tài)代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } //使用cglib return new ObjenesisCglibAopProxy(config); } else { //使用jdk動(dòng)態(tài)代理 return new JdkDynamicAopProxy(config); } }

另外AopProxy也是一個(gè)策略接口類,具體實(shí)現(xiàn)的策略為JdkDynamicAopProxy,CglibAopProxy,ObjenesisCglibAopProxy。

6.4 Tomcat中Digester解析server.xml

tomcat中的Digester是為了解析server.xml的,其中每個(gè)元素都有一個(gè)解析規(guī)則就是Rule ,類圖如下:

DigestER一開始先指定不同的解析策略(Rule),然后在具體解析Server.xml時(shí)候根據(jù)節(jié)點(diǎn)不同使用不同解析策略來解析節(jié)點(diǎn)。

如圖在解析每個(gè)節(jié)點(diǎn)時(shí)候會(huì)先找到該節(jié)點(diǎn)對(duì)應(yīng)的解析策略,然后循環(huán)去調(diào)用所有解析策略的方法去處理。

6.5 使用場景

運(yùn)行時(shí)根據(jù)條件的不同使用不同的策略處理一個(gè)事情,與責(zé)任鏈不同在于,責(zé)任鏈?zhǔn)且粋€(gè)鏈條,一個(gè)事情可以被責(zé)任鏈里面所有節(jié)點(diǎn)處理,而策略模式則是只有有一個(gè)對(duì)象來處理。

七、 門面模式(Facade Pattern)

7.1 介紹

門面模式是一種結(jié)構(gòu)性模式,它通過新增一個(gè)門面類對(duì)外暴露系統(tǒng)提供的一部分功能,或者屏蔽了內(nèi)部系統(tǒng)的復(fù)雜性,對(duì)外部僅僅暴露一個(gè)簡單的接口,或者通過調(diào)用不同的服務(wù)對(duì)外提供統(tǒng)一的接口,讓使用者對(duì)這些內(nèi)部服務(wù)透明化。

7.2 模板引擎Velocity中門面模式使用

Velocity里面的VelocityEngine和Velocity類都是RuntimeInstance類的門面,后者提供了模板渲染的所有功能,前兩者則是內(nèi)部維護(hù)RuntimeInstance的實(shí)例,具體工作還是委托給RuntimeInstance來實(shí)現(xiàn)。

關(guān)于Veloctiy可以參考:https://www.atatech.org/articles/78435

如圖 RuntimeInstance提供了Velocity引擎的所用功能,VelocityEngine內(nèi)部直接引用了RuntimeInstance的一個(gè)實(shí)例,VelocityEngine對(duì)外暴露的服務(wù)都是委托RuntimeInstance實(shí)現(xiàn),并且每次new一個(gè)VelocityEngine內(nèi)部都會(huì)有RuntimeInstance的一個(gè)實(shí)例被創(chuàng)建。而Velocity類調(diào)用了單例模式類RuntimeSingleton里面的方法,RuntimeSingleton又是RuntimeInstance的一個(gè)單例模式。

7.3 使用場景

  • 當(dāng)需要對(duì)外屏蔽一個(gè)系統(tǒng)的復(fù)雜性時(shí)候可以考慮使用門面模式對(duì)外提供簡單可讀性高的接口類。

  • 當(dāng)需要對(duì)外部暴露系統(tǒng)一部分權(quán)限的接口時(shí)候可以考慮使用門面模式減少系統(tǒng)權(quán)限。

  • 當(dāng)系統(tǒng)需要調(diào)用不同服務(wù)匯總后在對(duì)外提供服務(wù)時(shí)候可以考慮使用門面模式對(duì)外屏蔽細(xì)節(jié),只暴露一個(gè)接口。

八、裝飾器模式(Decorator Pattern)

8.1 介紹

裝飾器模式是一種結(jié)構(gòu)性模式,它的作用是對(duì)對(duì)象已有功能進(jìn)行增強(qiáng),但是不改變?cè)袑?duì)象結(jié)構(gòu)。這避免了通過繼承方式進(jìn)行功能擴(kuò)充導(dǎo)致的類體系臃腫。

8.2 Spring中BeanDefinitionDecorator

先看下類圖:

如圖ScopedProxyBeanDefinitionDecorator實(shí)現(xiàn)了decorate方法用來對(duì)scope作用域?yàn)閞equest的bean定義進(jìn)行包裝。

具體時(shí)序圖為:

class ScopedProxyBeanDefinitionDecorator implements BeanDefinitionDecorator { private static final String PROXY_TARGET_CLASS = "proxy-target-class"; @Override public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { boolean proxyTargetClass = true; if (node instanceof Element) { Element ele = (Element) node; if (ele.hasAttribute(PROXY_TARGET_CLASS)) { proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS)); } } // 創(chuàng)建scoped的代理類,并注冊(cè)到容器 BeanDefinitionHolder holder = ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass); String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName()); parserContext.getReaderContext().fireComponentRegistered( new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName)); return holder; }}

關(guān)于ScopedProxyBeanDefinitionDecorator干啥用的呢:

   

其實(shí)就是處理

的,具體作用是包裝lavaPvgInfo的bean定義為ScopedProxyFactoryBean,作用是實(shí)現(xiàn)request作用域bean。

8.3 commons-collections包中ListUtils

如圖

ListUtils中的四個(gè)方法分別依賴list的四種裝飾器類對(duì)List功能進(jìn)行擴(kuò)充和限制。

其中FixedSizeList類通過禁止add/remove操作保證list的大小固定,但是可以修改元素內(nèi)容。

其中UnmodifiableList類通過禁用add,clear,remove,set,保證list的內(nèi)容不被修改。

其中SynchronizedList類通過使用Lock 來保證add,set,get,remove等的同步安全。

其中LazyList類則當(dāng)調(diào)用get方法發(fā)現(xiàn)list里面不存在對(duì)象時(shí)候,自動(dòng)使用factory創(chuàng)建對(duì)象。

8.4 使用場景

  • 在不改變?cè)蓄惤Y(jié)構(gòu)基礎(chǔ)上,新增或者限制或者改造功能時(shí)候。

九、適配器模式(Adapter Pattern)

9.1 介紹

適配器模式屬于結(jié)構(gòu)性模式,它為兩個(gè)不同接口之間互通提供了一種手段。

9.2 Spring中MethodInterceptor適配器

在Spring Aop框架中,MethodInterceptor接口被用來攔截指定的方法,對(duì)方法進(jìn)行增強(qiáng)。

大家都知道在Aop中每個(gè)advistor 里面會(huì)有一個(gè)advice具體做切面動(dòng)作,Spring提供了AspectJAfterReturningAdvice,AspectJMethodBeforeAdvice,AspectJAroundAdvice,AspectJAfterAdvice這幾個(gè)advice,在XML 配置aop時(shí)候會(huì)指定,,,,其實(shí)內(nèi)部就是創(chuàng)建上面對(duì)應(yīng)的這些advice。

從圖知道AspectJAfterReturningAdvice和AspectJMethodBeforeAdvice沒有實(shí)現(xiàn)MethodInterceptor接口,其他兩者則實(shí)現(xiàn)了該接口。而Spring Aop的方法攔截器卻必須是實(shí)現(xiàn)了MethodInterceptor的,所以Spring提供了對(duì)應(yīng)的適配器來適配這個(gè)問題,分別是MethodBeforeAdviceAdapter和AfterReturningAdviceAdapter和ThrowsAdviceAdapter。

看下DefaultAdvisorAdapterRegistry的 getInterceptors方法:

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List interceptors = new ArrayList(3); //從advistor中獲取advice Advice advice = advisor.getAdvice(); //如果實(shí)現(xiàn)了MethodInterceptor則直接加入,比如AspectJAroundAdvice,AspectJAfterAdvice if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } //否者看是否有當(dāng)前advice的適配器,首先檢驗(yàn)是否支持,支持則返回對(duì)應(yīng)的適配器 for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[interceptors.size()]);}

以MethodBeforeAdviceAdapter為例子看下:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); }}public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { private MethodBeforeAdvice advice; /** * Create a new MethodBeforeAdviceInterceptor for the given advice. * @param advice the MethodBeforeAdvice to wrap */ public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); }}

可知MethodBeforeAdviceInterceptor繼承了MethodInterceptor作為了一個(gè)適配器內(nèi)部委托請(qǐng)求給MethodBeforeAdvice。

9.3 使用場景

  • 兩個(gè)系統(tǒng)交互時(shí)候由于接口參數(shù)不一樣沒辦法直接對(duì)接,則可以搞個(gè)適配器接口做參數(shù)轉(zhuǎn)換。

  • 適配器模式經(jīng)常是在一個(gè)系統(tǒng)或者設(shè)計(jì)已經(jīng)定型時(shí)候用的,而不是在初始設(shè)計(jì)時(shí)候。一般是因?yàn)椴挥绊懍F(xiàn)在業(yè)務(wù)情況下,通過適配方式統(tǒng)一接口

十、模板設(shè)計(jì)模式(Template Pattern)

10.1 前言

模板設(shè)計(jì)模式是一種行為設(shè)計(jì)模式,它使用一個(gè)抽象類定義了一個(gè)模板,這個(gè)模板里面定義了一系列的接口,子類則只需要繼承該抽象類并且根據(jù)需要重寫一部分接口。

10.2 ibatis2中AbstractDAOTemplate

如圖AbstractDAOTemplate是抽象模板類,里面定義了configure方法,configure方法里面定義了好多protected方法,其中就有些是抽象方法。類SpringDAOTemplate,IbatisDAOTemplate,GenericCIDAOTemplate,GenericSIDAOTemplate則繼承了AbstractDAOTemplate類并重寫了一部分方法。

10.3 Tomcat中Digester里面的Rule

tomcat中的Digester是為了解析server.xml的,其中每個(gè)元素都有一個(gè)解析規(guī)則就是Rule ,類圖如下:

如圖:Rule是抽象類,對(duì)于每個(gè)解析的節(jié)點(diǎn)來說Rule提供了解析所需所有的方法,而他的子類則根據(jù)自己的特殊性重寫一部分方法來支持自己的特性。

10.4 Tomcat中Endpoint

如圖AbstractEndpoint是個(gè)抽象類,定義了Endpoint的所有接口,然后JIoEndpoint繼承了該類并且重寫了一部分重要的方法實(shí)現(xiàn)了BIO方式endpoint,NioEndpoint則重寫了方法實(shí)現(xiàn)了NIO的endpoint。

10.5使用場景

  • 當(dāng)多個(gè)子類具有共同的操作流程邏輯,并且其中某些流程節(jié)點(diǎn)操作需要自己定制化時(shí)候。

十一、 建造者模式(Builder Pattern)

11.1 前言

建造者模式是一種創(chuàng)建型模式,將一個(gè)復(fù)制對(duì)象的創(chuàng)建屏蔽到接口內(nèi)部,用戶使用時(shí)候只需要傳遞固定的參數(shù),內(nèi)部就會(huì)執(zhí)行復(fù)雜邏輯后返回給用戶需要的對(duì)象,用戶不需要知道創(chuàng)建的細(xì)節(jié)。

11.2 Mybatis中的SqlSessionFactoryBuilder

如圖mybaits中的SqlSessionFactoryBuilder就是典型的創(chuàng)建者模式,他內(nèi)部有多個(gè)build方法,根據(jù)參數(shù)的不同創(chuàng)建出SqlSessionFactory對(duì)象,使用者只需要傳遞具體參數(shù)而不用關(guān)心內(nèi)部是如何創(chuàng)建出需要的對(duì)象的。SqlSessionFactoryBean大家應(yīng)該很熟悉,在xml里面配置的。

11.3 使用場景

  • 當(dāng)一個(gè)對(duì)象比較復(fù)雜并且容易出錯(cuò)時(shí)候,可以考慮這種模式去屏蔽創(chuàng)造細(xì)節(jié)。

十二、 觀察者模式(Observer Pattern)

12.1 前言

觀察者模式是一種行為模式,它定義了當(dāng)一個(gè)對(duì)象的狀態(tài)或者屬性發(fā)生變化時(shí)候,通知其他對(duì)這些狀態(tài)感興趣的對(duì)象。觀察者模式也叫發(fā)布-訂閱模式,就是說當(dāng)你訂閱了摸一個(gè)主體時(shí)候,如果發(fā)布者改變了主題內(nèi)容,那么所有訂閱這個(gè)主體者都會(huì)受到通知。

12.2 Spring中ApplicationListener

如圖 黃色部分的listener們可以認(rèn)為是訂閱者,紅色的context是發(fā)布者,context在IOC不同狀態(tài)會(huì)給這些訂閱者發(fā)布不同的消息通知訂閱者容器狀態(tài)。藍(lán)色的為具體的事件(這里為容器不同狀態(tài)),其中ContextRefreshedEvent是IOC刷新完成(也就是bean解析完成,創(chuàng)建完畢并且autowired完成)后的事件這個(gè)經(jīng)常用。

這里context并不是直接來管理黃色的listener訂閱者的,而是委托給了綠色的部分,該部分是可以增加刪除訂閱者,并且發(fā)布事件給訂閱者。

其實(shí)Tomact中的Lifecycle也是這種機(jī)制,這里不再贅述。

12.3 使用場景

  • 滿足發(fā)布-訂閱條件的,當(dāng)一個(gè)對(duì)象狀態(tài)或者屬性變化,需要把這種變化通知到訂閱者時(shí)候。

十三、命令模式(Command Pattern)

13.1 介紹

命令模式是一種行為模式,通過把命令封裝為一個(gè)對(duì)象,命令發(fā)送者把命令對(duì)象發(fā)出后,就不去管是誰來接受處理這個(gè)命令,命令接受者接受到命令對(duì)象后進(jìn)行處理,也不用管命令是誰發(fā)出的,所以命令模式實(shí)現(xiàn)了發(fā)送者與接受者之間的解耦,而具體把命令發(fā)送給誰還需要一個(gè)控制器。

13.2 Tomcat中命令模式

tomcat作為一個(gè)服務(wù)器本身會(huì)接受外部大量請(qǐng)求,當(dāng)一個(gè)請(qǐng)求過來后tomcat根據(jù)域名去找對(duì)應(yīng)的host,找到host后會(huì)根據(jù)應(yīng)用名去找具體的context(應(yīng)用),然后具體應(yīng)用處理請(qǐng)求。對(duì)于具體host來說他不關(guān)心這個(gè)請(qǐng)求是誰給的,對(duì)應(yīng)請(qǐng)求來說他不必關(guān)心誰來處理,但是兩者是通過request封裝請(qǐng)求對(duì)象進(jìn)行關(guān)聯(lián)起來。

tomcat中Connector作為命令發(fā)出者,Connector接受到請(qǐng)求后把請(qǐng)求內(nèi)容封裝為request對(duì)象(命令對(duì)象),然后使用CoyoteAdapter作為分發(fā)器把請(qǐng)求具體發(fā)配到具體的host,host在根據(jù)request對(duì)象找到具體的context,至此找到了具體的應(yīng)用,交給具體應(yīng)用處理。

另外對(duì)于使用springmvc的應(yīng)用來說,上面找到具體應(yīng)用,但是具體交給那個(gè)controller來處理那,這是不是也是命令模式的使用那。

13.3 使用場景

  • 當(dāng)事件發(fā)送者和接受者直接需要完全解耦(直接并不存在引用關(guān)系)時(shí)候。

十四、總結(jié)

設(shè)計(jì)模式中每一個(gè)模式都描述了在我們工作中不斷重復(fù)發(fā)生的問題,以及問題的解決方案,所以真正掌握設(shè)計(jì)模式可以避免我們做不必要的重復(fù)勞動(dòng)。


網(wǎng)站欄目:【分享】我在阿里工作十年里接觸過的Java框架設(shè)計(jì)模式
當(dāng)前地址:http://m.5511xx.com/article/cdjssco.html