少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          常用鏈接

          留言簿(22)

          我參與的團(tuán)隊(duì)

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          #

          最近因?yàn)轫?xiàng)目需要,簡單的試用了兩款高可用開源方案:Keepalived和Heartbeat。兩者都很流行,但差異還是很大的,現(xiàn)將試用過程中的感受以及相關(guān)知識(shí)點(diǎn)簡單總結(jié)一下,供大家選擇方案的時(shí)候參考。
          1)Keepalived使用更簡單:從安裝、配置、使用、維護(hù)等角度上對(duì)比,Keepalived都比Heartbeat要簡單得多,尤其是Heartbeat2.1.4后拆分成3個(gè)子項(xiàng)目,安裝、配置、使用都比較復(fù)雜,尤其是出問題的時(shí)候,都不知道具體是哪個(gè)子系統(tǒng)出問題了;而Keepalived只有1個(gè)安裝文件、1個(gè)配置文件,配置文件也簡單很多;
          2)Heartbeat功能更強(qiáng)大:Heartbeat雖然復(fù)雜,但功能更強(qiáng)大,配套工具更全,適合做大型集群管理,而Keepalived主要用于集群倒換,基本沒有管理功能;
          3)協(xié)議不同:Keepalived使用VRRP協(xié)議進(jìn)行通信和選舉,Heartbeat使用心跳進(jìn)行通信和選舉;Heartbeat除了走網(wǎng)絡(luò)外,還可以通過串口通信,貌似更可靠;
          4)使用方式基本類似:如果要基于兩者設(shè)計(jì)高可用方案,最終都要根據(jù)業(yè)務(wù)需要寫自定義的腳本,Keepalived的腳本沒有任何約束,隨便怎么寫都可以;Heartbeat的腳本有約束,即要支持service start/stop/restart這種方式,而且Heartbeart提供了很多默認(rèn)腳本,簡單的綁定ip,啟動(dòng)apache等操作都已經(jīng)有了;
          使用建議:優(yōu)先使用Keepalived,當(dāng)Keepalived不夠用的時(shí)候才選擇Heartbeat
          posted @ 2015-07-26 20:42 abin 閱讀(796) | 評(píng)論 (1)編輯 收藏

          1、StatefulJob
          implements StatefulJob使Job成為有狀態(tài)的,順序執(zhí)行 
          同一個(gè)有狀態(tài)的job實(shí)例不存在并發(fā),無狀態(tài)的job的并發(fā)數(shù)由上面配置的線程數(shù)決定。不想并發(fā)的話,設(shè)置成1,第二個(gè)線程在前一個(gè)執(zhí)行完以后觸發(fā)執(zhí)行。
          線程數(shù)大于1時(shí),如果存在空閑線程,則到執(zhí)行時(shí)間點(diǎn)即觸發(fā)執(zhí)行。

          2、
          MethodInvokingJobDetailFactoryBean
          MethodInvokingJobDetailFactoryBean的并發(fā)問題
          大家在使用quartz的時(shí)候,一般只設(shè)置了“targetObject”和“targetMethod”,MethodInvokingJobDetailFactoryBean類默認(rèn)是并發(fā)執(zhí)行的,這時(shí)候如果不設(shè)置“concurrent”為false,很可能帶來并發(fā)或者死鎖的問題,而且?guī)茁瘦^小,不容易復(fù)現(xiàn),請(qǐng)大家使用的時(shí)候注意設(shè)置“concurrent”。
           
              <bean id="cpm.MessageJobFactoryBean" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
                  <property name="targetObject" ref="cpm.MessageJob"/>
                  <property name="targetMethod" value="execute"/>
                  <property name="concurrent" value="false"/>
              </bean>
          concurrent   同時(shí)發(fā)生
           concurrent:對(duì)于相同的JobDetail,當(dāng)指定多個(gè)Trigger時(shí), 很可能第一個(gè)job完成之前,第二個(gè)job就開始了。
           定concurrent設(shè)為false,多個(gè)job不會(huì)并發(fā)運(yùn)行,第二個(gè)job將不會(huì)在第一個(gè)job完成之前開始




          防止job并行運(yùn)行的幾種解決方案 
          一、JOB State 
          在通過MethodInvokingJobDetailFactoryBean在運(yùn)行中動(dòng)態(tài)生成的Job,配置的xml文件有個(gè)concurrent屬性,表示job是否可以并行運(yùn)行:如果一個(gè)job的業(yè)務(wù)處理發(fā)費(fèi)的時(shí)間超過了job的啟動(dòng)的間隔時(shí)間(repeatInterval),這個(gè)屬性非常有用。如果為false,那么,在這種情況下,當(dāng)前job還在運(yùn)行,那么下一個(gè)job只能延時(shí)運(yùn)行。如果為true,那么job就會(huì)并行運(yùn)行。在實(shí)際的應(yīng)用中應(yīng)該配置為true/false,要根據(jù)需要了(廢話)。 
          二、如果通過繼承QuartzJobBean實(shí)現(xiàn)job的話,默認(rèn)情況下QuartzJobBean是implements org.quartz.Job接口的,也就是說job示例是stateless的,會(huì)出現(xiàn)前面所述的并行情況。而代碼中卻要求job任務(wù)必需串行,解決辦法:在job子類中繼續(xù)implements org.quartz.StatefulJob。那么這個(gè)job實(shí)例變成了Stateful,job任務(wù)也就是串行的了。
          注: 
          在Quartz中,如果實(shí)現(xiàn)org.quartz.Job接口,那么這個(gè)job是stateless的,job實(shí)例的參數(shù)不能在多個(gè)任務(wù)之間共享,如果實(shí)現(xiàn)org.quartz.StatefulJob,這個(gè)job是個(gè)單例的,job實(shí)例的屬性可以從當(dāng)前任務(wù)傳遞到下一個(gè)任務(wù)。 


          spring和quartz的整合對(duì)版本是有要求的。
          spring3.1以下的版本必須使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然會(huì)出錯(cuò)。

          至于原因,則是spring對(duì)于quartz的支持實(shí)現(xiàn),org.springframework.scheduling.quartz.CronTriggerBean繼承了org.quartz.CronTrigger,在quartz1.x系列中org.quartz.CronTrigger是個(gè)類,而在quartz2.x系列中org.quartz.CronTrigger變成了接口,從而造成無法用spring的方式配置quartz的觸發(fā)器(trigger)。

          在Spring中使用Quartz有兩種方式實(shí)現(xiàn):第一種是任務(wù)類繼承QuartzJobBean,第二種則是在配置文件里定義任務(wù)類和要執(zhí)行的方法,類和方法可以是普通類。很顯然,第二種方式遠(yuǎn)比第一種方式來的靈活。



          MethodInvokingJobDetailFactoryBean中concurrent和shouldRecover屬性的作用
          解釋 concurrent為true,則允許一個(gè)QuartzJob并發(fā)執(zhí)行,否則就是順序執(zhí)行。例如QuartzJob A執(zhí)行時(shí)間為15秒,配置為每10秒執(zhí)行一次;如果concurrent為true,則0秒的時(shí)候啟動(dòng)一次A,10秒的時(shí)候再啟動(dòng)一次A,20秒的時(shí)候再啟動(dòng)一次A,不管前面啟動(dòng)的A有沒有執(zhí)行完;如果concurrent為false,則0秒的時(shí)候啟動(dòng)一次A,15秒的時(shí)候A執(zhí)行完畢,再第二次啟動(dòng)A。
          shouldRecover屬性為true,則當(dāng)Quartz服務(wù)被中止后,再次啟動(dòng)或集群中其他機(jī)器接手任務(wù)時(shí)會(huì)嘗試恢復(fù)執(zhí)行之前未完成的所有任務(wù)。例如QuartzJob B,在每次00秒的時(shí)候啟動(dòng),假如在03:00的任務(wù)執(zhí)行完之后服務(wù)器1被中止,服務(wù)器2在05:15的時(shí)候才接手;如果shouldRecover屬性為true,則服務(wù)器2會(huì)嘗試著補(bǔ)回原來在04:00和05:00的時(shí)候應(yīng)該做的任務(wù),如果shouldRecover屬性為false,則服務(wù)器2只會(huì)從06:00的時(shí)候再執(zhí)行B。


          Quartz集群只支持JDBCJobStore存儲(chǔ)方式,而MethodInvokingJobDetailFactoryBean不能序列化存儲(chǔ)job數(shù)據(jù)到數(shù)據(jù)庫,
          重寫 quartz 的 QuartzJobBean 類 
          原因是在使用 quartz+spring 把 quartz 的 task 實(shí)例化進(jìn)入數(shù)據(jù)庫時(shí),會(huì)產(chǎn)生: serializable 的錯(cuò)誤,原因在于:
          這個(gè) MethodInvokingJobDetailFactoryBean 類中的 methodInvoking 方法,是不支持序列化的,因此在把 QUARTZ 的 TASK 序列化進(jìn)入數(shù)據(jù)庫時(shí)就會(huì)拋錯(cuò)。網(wǎng)上有說把 SPRING 源碼拿來,修改一下這個(gè)方案,然后再打包成 SPRING.jar 發(fā)布,這些都是不好的方法,是不安全的。
          必須根據(jù) QuartzJobBean 來重寫一個(gè)自己的類 。


          posted @ 2015-07-26 01:39 abin 閱讀(2123) | 評(píng)論 (0)編輯 收藏

          QRTZ_CALENDARS 以 Blob 類型存儲(chǔ) Quartz 的 Calendar 信息 
          QRTZ_CRON_TRIGGERS 存儲(chǔ) Cron Trigger,包括 Cron表達(dá)式和時(shí)區(qū)信息 
          QRTZ_FIRED_TRIGGERS 存儲(chǔ)與已觸發(fā)的 Trigger 相關(guān)的狀態(tài)信息,以及相聯(lián) Job的執(zhí)行信息QRTZ_PAUSED_TRIGGER_GRPS 存儲(chǔ)已暫停的 Trigger 組的信息 
          QRTZ_SCHEDULER_STATE 存儲(chǔ)少量的有關(guān) Scheduler 的狀態(tài)信息,和別的 Scheduler實(shí)例(假如是用于一個(gè)集群中) 
          QRTZ_LOCKS 存儲(chǔ)程序的觀鎖的信息(假如使用了悲觀鎖) 
          QRTZ_JOB_DETAILS 存儲(chǔ)每一個(gè)已配置的 Job 的詳細(xì)信息 
          QRTZ_JOB_LISTENERS 存儲(chǔ)有關(guān)已配置的 JobListener 的信息 
          QRTZ_SIMPLE_TRIGGERS 存儲(chǔ)簡單的Trigger,包括重復(fù)次數(shù),間隔,以及已觸的次數(shù) 
          QRTZ_BLOG_TRIGGERS Trigger 作為 Blob 類型存儲(chǔ)(用于 Quartz 用戶用 JDBC創(chuàng)建他們自己定制的 Trigger 類型,JobStore 并不知道如何存儲(chǔ)實(shí)例的時(shí)候) 
          QRTZ_TRIGGER_LISTENERS 存儲(chǔ)已配置的 TriggerListener 的信息 
          QRTZ_TRIGGERS 存儲(chǔ)已配置的 Trigger 的信息 
          --------------------------------------------------------------------------------------------------
          quartz 持久化數(shù)據(jù)庫表格字段解釋
          建表,SQL語句在quartz-1.6.6\docs\dbTables文件夾中可以找到,介紹下主要的幾張表: 
                 表qrtz_job_details: 保存job詳細(xì)信息,該表需要用戶根據(jù)實(shí)際情況初始化 
                 job_name:集群中job的名字,該名字用戶自己可以隨意定制,無強(qiáng)行要求 
                 job_group:集群中job的所屬組的名字,該名字用戶自己隨意定制,無強(qiáng)行要求 
                 job_class_name:集群中個(gè)note job實(shí)現(xiàn)類的完全包名,quartz就是根據(jù)這個(gè)路徑到classpath找到該job類 
                 is_durable:是否持久化,把該屬性設(shè)置為1,quartz會(huì)把job持久化到數(shù)據(jù)庫中 
                 job_data:一個(gè)blob字段,存放持久化job對(duì)象 

                 表qrtz_triggers: 保存trigger信息 
                 trigger_name: trigger的名字,該名字用戶自己可以隨意定制,無強(qiáng)行要求 
                 trigger_group:trigger所屬組的名字,該名字用戶自己隨意定制,無強(qiáng)行要求 
                 job_name: qrtz_job_details表job_name的外鍵 
                 job_group: qrtz_job_details表job_group的外鍵 
                 trigger_state:當(dāng)前trigger狀態(tài),設(shè)置為ACQUIRED,如果設(shè)置為WAITING,則job不會(huì)觸發(fā) 
                 trigger_cron:觸發(fā)器類型,使用cron表達(dá)式 

                 表qrtz_cron_triggers:存儲(chǔ)cron表達(dá)式表 
                 trigger_name: qrtz_triggers表trigger_name的外鍵 
                 trigger_group: qrtz_triggers表trigger_group的外鍵 
                 cron_expression:cron表達(dá)式 
                 
                 表qrtz_scheduler_state:存儲(chǔ)集群中note實(shí)例信息,quartz會(huì)定時(shí)讀取該表的信息判斷集群中每個(gè)實(shí)例的當(dāng)前狀態(tài) 
                 instance_name:之前配置文件中org.quartz.scheduler.instanceId配置的名字,就會(huì)寫入該字段,如果設(shè)置為AUTO,quartz會(huì)根據(jù)物理機(jī)名和當(dāng)前時(shí)間產(chǎn)生一個(gè)名字 
                 last_checkin_time:上次檢查時(shí)間 
                 checkin_interval:檢查間隔時(shí)間 

          步驟4
           配置quartz.properties文件:
          #調(diào)度標(biāo)識(shí)名 集群中每一個(gè)實(shí)例都必須使用相同的名稱 org.quartz.scheduler.instanceName = scheduler
          #ID設(shè)置為自動(dòng)獲取 每一個(gè)必須不同 org.quartz.scheduler.instanceId = AUTO
          #數(shù)據(jù)保存方式為持久化 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
          #數(shù)據(jù)庫平臺(tái) org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate #數(shù)據(jù)庫別名 隨便取org.quartz.jobStore.dataSource = myXADS
          #表的前綴 org.quartz.jobStore.tablePrefix = QRTZ_
          #設(shè)置為TRUE不會(huì)出現(xiàn)序列化非字符串類到 BLOB 時(shí)產(chǎn)生的類版本問題 org.quartz.jobStore.useProperties = true
          #加入集群 org.quartz.jobStore.isClustered = true
          #調(diào)度實(shí)例失效的檢查時(shí)間間隔 org.quartz.jobStore.clusterCheckinInterval = 20000 
          #容許的最大作業(yè)延長時(shí)間 org.quartz.jobStore.misfireThreshold = 60000
          #ThreadPool 實(shí)現(xiàn)的類名 org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
          #線程數(shù)量 org.quartz.threadPool.threadCount = 10
          #線程優(yōu)先級(jí) org.quartz.threadPool.threadPriority = 5
          #自創(chuàng)建父線程 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true 
          #設(shè)置數(shù)據(jù)源org.quartz.dataSource.myXADS.jndiURL = CT
          #jbdi類名 org.quartz.dataSource.myXADS.java.naming.factory.initial = weblogic.jndi.WLInitialContextFactory #URLorg.quartz.dataSource.myXADS.java.naming.provider.url = t3://localhost:7001

          【注】:在J2EE工程中如果想用數(shù)據(jù)庫管理Quartz的相關(guān)信息,就一定要配置數(shù)據(jù)源,這是Quartz的要求。
          posted @ 2015-07-23 15:31 abin 閱讀(655) | 評(píng)論 (0)編輯 收藏

          1、下載一個(gè)jrebel的文件,解壓到D:\Sys\jrebel6.0.0-crack,在eclipse的classpath路徑下面配置rebel.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://www.zeroturnaround.com/alderaan/rebel-2_0.xsd">
          <classpath>
          <dir name="D:\SystemFile\EclipseWorkspace\SpringAQConsume\target">
          </dir>
          </classpath>
          <web>
          <link target="/">
          <dir name="D:\SystemFile\EclipseWorkspace\SpringAQConsume\src\main\webapp">
          </dir>
          </link>
          </web>
          </application>

          2、在tomcat里面配置
           -javaagent:D:\Sys\jrebel6.0.0-crack\jrebel.jar -noverify  -Xbootclasspath/p:D:\Sys\jrebel6.0.0-crack\rebelboot.jar
           -javaagent:D:\Sys\jrebel-6.0.2\jrebel.jar -noverify  -Xbootclasspath/p:D:\Sys\jrebel-6.0.2\rebelboot.jar


          *********6.2.2需要以下設(shè)置**********
          -noverify
          -Djavaagent:D:/Sys\server/JRebel/JRebel6.2.0/jrebel.jar
          -DXbootclasspath/p:D:\Sys\server\JRebel\JRebel6.2.0\rebelboot.jar
          -Drebel.generate.show=true
          -Drebel.spring_plugin=true
          -Drebel.aspectj_plugin=true
          -Drebel.cxf_plugin=true
          -Drebel.logback_plugin=true
          -Drebel.mybatis_plugin=true
          -Xdebug -Djava.compiler=NONE -DXrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n
          -Drebel.dirs=D:\SystemFile\EclipseWorkspace\integrate-svr\integrate-main\target\classes
          -Dmyproject.root=D:\SystemFile\EclipseWorkspace\integrate-svr
          -Drebel.disable_update=true
          posted @ 2015-06-24 11:43 abin 閱讀(3288) | 評(píng)論 (0)編輯 收藏

          《秒殺系統(tǒng)架構(gòu)優(yōu)化思路》


          上周參加Qcon,有個(gè)兄弟分享秒殺系統(tǒng)的優(yōu)化,其觀點(diǎn)有些贊同,大部分觀點(diǎn)卻并不同意,結(jié)合自己的經(jīng)驗(yàn),談?wù)勛约旱囊恍┛捶ā?/span>


          一、為什么難

          秒殺系統(tǒng)難做的原因:庫存只有一份,所有人會(huì)在集中的時(shí)間讀和寫這些數(shù)據(jù)。

          例如小米手機(jī)每周二的秒殺,可能手機(jī)只有1萬部,但瞬時(shí)進(jìn)入的流量可能是幾百幾千萬。

          又例如12306搶票,亦與秒殺類似,瞬時(shí)流量更甚。


          二、常見架構(gòu)


          流量到了億級(jí)別,常見站點(diǎn)架構(gòu)如上:

          1)瀏覽器端,最上層,會(huì)執(zhí)行到一些JS代碼

          2)站點(diǎn)層,這一層會(huì)訪問后端數(shù)據(jù),拼html頁面返回給瀏覽器

          3)服務(wù)層,向上游屏蔽底層數(shù)據(jù)細(xì)節(jié)

          4)數(shù)據(jù)層,最終的庫存是存在這里的,mysql是一個(gè)典型


          三、優(yōu)化方向

          1)將請(qǐng)求盡量攔截在系統(tǒng)上游:傳統(tǒng)秒殺系統(tǒng)之所以掛,請(qǐng)求都?jí)旱沽撕蠖藬?shù)據(jù)層,數(shù)據(jù)讀寫鎖沖突嚴(yán)重,并發(fā)高響應(yīng)慢,幾乎所有請(qǐng)求都超時(shí),流量雖大,下單成功的有效流量甚小【一趟火車其實(shí)只有2000張票,200w個(gè)人來買,基本沒有人能買成功,請(qǐng)求有效率為0】

          2)充分利用緩存:這是一個(gè)典型的讀多些少的應(yīng)用場(chǎng)景【一趟火車其實(shí)只有2000張票,200w個(gè)人來買,最多2000個(gè)人下單成功,其他人都是查詢庫存,寫比例只有0.1%,讀比例占99.9%】,非常適合使用緩存


          四、優(yōu)化細(xì)節(jié)

          4.1)瀏覽器層請(qǐng)求攔截

          點(diǎn)擊了“查詢”按鈕之后,系統(tǒng)那個(gè)卡呀,進(jìn)度條漲的慢呀,作為用戶,會(huì)不自覺的再去點(diǎn)擊“查詢”,繼續(xù)點(diǎn),繼續(xù)點(diǎn),點(diǎn)點(diǎn)點(diǎn)。。。有用么?平白無故的增加了系統(tǒng)負(fù)載(一個(gè)用戶點(diǎn)5次,80%的請(qǐng)求是這么多出來的),怎么整?

          a)產(chǎn)品層面,用戶點(diǎn)擊“查詢”或者“購票”后,按鈕置灰,禁止用戶重復(fù)提交請(qǐng)求

          b)JS層面,限制用戶在x秒之內(nèi)只能提交一次請(qǐng)求

          如此限流,80%流量已攔


          4.2)站點(diǎn)層請(qǐng)求攔截與頁面緩存

          瀏覽器層的請(qǐng)求攔截,只能攔住小白用戶(不過這是99%的用戶喲),高端的程序員根本不吃這一套,寫個(gè)for循環(huán),直接調(diào)用你后端的http請(qǐng)求,怎么整?

          a)同一個(gè)uid,限制訪問頻度,做頁面緩存,x秒內(nèi)到達(dá)站點(diǎn)層的請(qǐng)求,均返回同一頁面

          b)同一個(gè)item的查詢,例如手機(jī)車次,做頁面緩存,x秒內(nèi)到達(dá)站點(diǎn)層的請(qǐng)求,均返回同一頁面

          如此限流,又有99%的流量會(huì)被攔截在站點(diǎn)層


          4.3)服務(wù)層請(qǐng)求攔截與數(shù)據(jù)緩存

          站點(diǎn)層的請(qǐng)求攔截,只能攔住普通程序員,高級(jí)黑客,假設(shè)他控制了10w臺(tái)肉雞(并且假設(shè)買票不需要實(shí)名認(rèn)證),這下uid的限制不行了吧?怎么整?

          a)大哥,我是服務(wù)層,我清楚的知道小米只有1萬部手機(jī),我清楚的知道一列火車只有2000張車票,我透10w個(gè)請(qǐng)求去數(shù)據(jù)庫有什么意義呢?對(duì)于寫請(qǐng)求,做請(qǐng)求隊(duì)列,每次只透過有限的寫請(qǐng)求去數(shù)據(jù)層,如果均成功再放下一批,如果庫存不夠則隊(duì)列里的寫請(qǐng)求全部返回“已售完”

          b)對(duì)于讀請(qǐng)求,還用說么?cache來抗,不管是memcached還是redis,單機(jī)抗個(gè)每秒10w應(yīng)該都是沒什么問題的

          如此限流,只有非常少的寫請(qǐng)求,和非常少的讀緩存mis的請(qǐng)求會(huì)透到數(shù)據(jù)層去,又有99.9%的請(qǐng)求被攔住了


          4.4)數(shù)據(jù)層閑庭信步

          到了數(shù)據(jù)這一層,幾乎就沒有什么請(qǐng)求了,單機(jī)也能扛得住,還是那句話,庫存是有限的,小米的產(chǎn)能有限,透過過多請(qǐng)求來數(shù)據(jù)庫沒有意義。


          五、總結(jié)

          沒什么總結(jié)了,上文應(yīng)該描述的非常清楚了,對(duì)于秒殺系統(tǒng),再次重復(fù)下筆者的兩個(gè)架構(gòu)優(yōu)化思路:

          1)盡量將請(qǐng)求攔截在系統(tǒng)上游

          2)讀多寫少的常用多使用緩存

          posted @ 2015-05-23 15:50 abin 閱讀(1367) | 評(píng)論 (0)編輯 收藏

          java 有for(;;)和 for(Object obj : List/Array)

          最明顯的一個(gè):前者是有范圍;后者是全部。

          就編碼來說各有好處:for更靈活,foreach更簡便

          for和foreach都是java中重要的集合遍歷方法 
          for循環(huán)中 你可以選擇從前往后遍歷,也可以從后往前遍歷,也可以不遍歷默寫值
          但是foreach只能從前往后遍歷,而且每一個(gè)都會(huì)遍歷一次,他們之間的選擇得看你項(xiàng)目程序中的需求而定
          JVM在解釋執(zhí)行行,都會(huì)將for與foreach解釋成iterator。

          總結(jié)如下:

          1.如果只是遍歷集合或者數(shù)組,用foreach好些,快些。

          2.如果對(duì)集合中的值進(jìn)行修改,就要用for循環(huán)了。
          其實(shí)foreach的內(nèi)部原理其實(shí)也是Iterator,但它不能像Iterator一樣可以人為的控制,而且也不能調(diào)用iterator.remove();
          更不能使用下標(biāo)來訪問每個(gè)元素,所以不能用于增加,刪除等復(fù)雜的操作。



          posted @ 2015-05-21 23:59 abin 閱讀(388) | 評(píng)論 (0)編輯 收藏

              Twitter-Snowflake算法產(chǎn)生的背景相當(dāng)簡單,為了滿足Twitter每秒上萬條消息的請(qǐng)求,每條消息都必須分配一條唯一的id,這些id還需要一些大致的順序(方便客戶端排序),并且在分布式系統(tǒng)中不同機(jī)器產(chǎn)生的id必須不同。

          生成的ID是64Bits整型數(shù),同時(shí)滿足高性能(>10K ids/s),低延遲(<2ms)和高可用。

          在分布式系統(tǒng)中,需要生成全局UID的場(chǎng)合還是比較多的,twitter的snowflake解決了這種需求,實(shí)現(xiàn)也還是很簡單的,除去配置信息,核心代碼就是毫秒級(jí)時(shí)間41位+機(jī)器ID 10位+毫秒內(nèi)序列12位。

          該項(xiàng)目地址為:https://github.com/twitter/snowflake是用Scala實(shí)現(xiàn)的。

          python版詳見開源項(xiàng)目https://github.com/erans/pysnowflake

          核心代碼為其IdWorker這個(gè)類實(shí)現(xiàn),其原理結(jié)構(gòu)如下,我分別用一個(gè)0表示一位,用—分割開部分的作用:

          0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---0000000000 00

          在上面的字符串中,第一位為未使用(實(shí)際上也可作為long的符號(hào)位),接下來的41位為毫秒級(jí)時(shí)間,然后5位datacenter標(biāo)識(shí)位,5位機(jī)器ID(并不算標(biāo)識(shí)符,實(shí)際是為線程標(biāo)識(shí)),然后12位該毫秒內(nèi)的當(dāng)前毫秒內(nèi)的計(jì)數(shù),加起來剛好64位,為一個(gè)Long型。

          這樣的好處是,整體上按照時(shí)間自增排序,并且整個(gè)分布式系統(tǒng)內(nèi)不會(huì)產(chǎn)生ID碰撞(由datacenter和機(jī)器ID作區(qū)分),并且效率較高,經(jīng)測(cè)試,snowflake每秒能夠產(chǎn)生26萬ID左右,完全滿足需要。

          1. 41位的時(shí)間序列(精確到毫秒,41位的長度可以使用69年) 

          2. 10位的機(jī)器標(biāo)識(shí)(10位的長度最多支持部署1024個(gè)節(jié)點(diǎn),支持多機(jī)房的分布式,需要使用zookeeper) 

          3. 12位的計(jì)數(shù)順序號(hào)(12位的計(jì)數(shù)順序號(hào)支持每個(gè)節(jié)點(diǎn)每毫秒產(chǎn)生4096個(gè)ID序號(hào)) 最高位是符號(hào)位,始終為0。

          //64--------63-----------22-----------12----------0
          //符號(hào)位 |41位時(shí)間 |10位機(jī)器碼 |12位自增碼|

          對(duì)twitter而言這樣的ID生成方案滿足:

          1.每秒能夠生成足夠的ID數(shù)。 2.生成的ID按照時(shí)間大致有序。

          用zookeeper的原因是需要獲取一個(gè)workerId,當(dāng)然你也可以給分布式節(jié)點(diǎn)手工指定不同的workderId,那樣就不需要用zookeeper了。

          一個(gè)server一個(gè)workerid, 用zookeeper做保證.


          除了最高位bit標(biāo)記為不可用以外,其余三組bit占位均可浮動(dòng),看具體的業(yè)務(wù)需求而定。默認(rèn)情況下41bit的時(shí)間戳可以支持該算法使用到2082年,10bit的工作機(jī)器id可以支持1023臺(tái)機(jī)器,序列號(hào)支持1毫秒產(chǎn)生4095個(gè)自增序列id
















          posted @ 2015-05-17 13:20 abin 閱讀(1209) | 評(píng)論 (0)編輯 收藏

          1.Http作為web服務(wù)的首選協(xié)議,居有4大優(yōu)點(diǎn):
             1)http非常簡單,以純文本(超文本)形式編碼的請(qǐng)求和響應(yīng)組成
             2)http是無狀態(tài)的。一旦發(fā)送了一個(gè)http請(qǐng)求,客戶和服務(wù)器之間的連接信息就會(huì)被釋放,有利于減少服務(wù)器資源的消耗。
             3)http的運(yùn)行端口80,在大多數(shù)防火墻上是公開的
             4)行業(yè)認(rèn)可。
            但是Http的缺點(diǎn):
             1)缺少對(duì)異步消息的支持
             2)消息傳輸?shù)牟豢煽啃?br />

          web service相對(duì)http (post/get)有好處嗎?

           

          1.接口中實(shí)現(xiàn)的方法和要求參數(shù)一目了然

          2.不用擔(dān)心大小寫問題

          3.不用擔(dān)心中文urlencode問題

          4.代碼中不用多次聲明認(rèn)證(賬號(hào),密碼)參數(shù)

          5.傳遞參數(shù)可以為數(shù)組,對(duì)象等...

          http和webservice的區(qū)別:
          1、http是采用get,post等方式傳輸數(shù)據(jù),而webservice是采用xml格式打包數(shù)據(jù),傳輸是基于http協(xié)議進(jìn)行傳輸。
          2、http直接傳輸數(shù)據(jù),而webservice是采用xml編解碼數(shù)據(jù),所以能速度上面有些慢。
          3、webservice可以直接傳輸數(shù)組或者對(duì)象的數(shù)據(jù)格式,實(shí)際現(xiàn)在常用的http+json也可以的,只是需要進(jìn)行字符串和各種格式的轉(zhuǎn)換。
          4、http傳輸占用的帶寬要比webservice占用的帶寬少。
          5、webservice支持用戶權(quán)限的驗(yàn)證,而http不支持直接的用戶權(quán)限驗(yàn)證。
          6、webservice接口中實(shí)現(xiàn)的方法和要求參數(shù)一目了然。


          HTTPS和HTTP的區(qū)別:
          https協(xié)議需要到ca申請(qǐng)證書,一般免費(fèi)證書很少,需要交費(fèi)。
          http是超文本傳輸協(xié)議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協(xié)議
          http和https使用的是完全不同的連接方式用的端口也不一樣,前者是80,后者是443。
          http的連接很簡單,是無狀態(tài)的
          HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議 要比http協(xié)議安全


          SSL協(xié)議基礎(chǔ)

          SSL協(xié)議位于TCP/IP協(xié)議與各種應(yīng)用層協(xié)議之間,本身又分為兩層:

          SSL記錄協(xié)議(SSL Record Protocol):建立在可靠傳輸層協(xié)議(TCP)之上,為上層協(xié)議提供數(shù)據(jù)封裝、壓縮、加密等基本功能。

          SSL握手協(xié)議(SSL Handshake Procotol):在SSL記錄協(xié)議之上,用于實(shí)際數(shù)據(jù)傳輸前,通訊雙方進(jìn)行身份認(rèn)證、協(xié)商加密算法、交換加密密鑰等。


          HTTPS通信過程:
          1.在服務(wù)器端存在一個(gè)公鑰及私鑰
          2.客戶端從服務(wù)器取得這個(gè)公鑰
          3.客戶端產(chǎn)生一個(gè)隨機(jī)的密鑰
          4.客戶端通過公鑰對(duì)密鑰加密(非對(duì)稱加密)
          5.客戶端發(fā)送到服務(wù)器端
          6.服務(wù)器端接受這個(gè)密鑰并且以后的服務(wù)器端和客戶端的數(shù)據(jù)全部通過這個(gè)密鑰加密(對(duì)稱加密)





















          posted @ 2015-05-10 11:27 abin 閱讀(1307) | 評(píng)論 (0)編輯 收藏

          Zookeeper有兩種運(yùn)行模式:

          獨(dú)立模式(standalone mode):只運(yùn)行在一臺(tái)服務(wù)器上,適合測(cè)試環(huán)境

          復(fù)制模式(replicated mode):運(yùn)行于一個(gè)集群上,適合生產(chǎn)環(huán)境,這個(gè)計(jì)算機(jī)集群被稱為一個(gè)“集合體”(ensemble)。Zookeeper通過復(fù)制來實(shí)現(xiàn)高可用性,只要集合體中半數(shù)以上的機(jī)器處于可用狀態(tài),它就能夠保證服務(wù)繼續(xù)。為什么一定要超過半數(shù)呢?這跟Zookeeper的復(fù)制策略有關(guān):zookeeper確保對(duì)znode樹的每一個(gè)修改都會(huì)被復(fù)制到集合體中超過半數(shù)的機(jī)器上。

          生產(chǎn)環(huán)境,zookeeper集群的服務(wù)器數(shù)目應(yīng)該是奇數(shù)。

          Zookeeper集群中的角色及其職責(zé)

          領(lǐng)導(dǎo)者

            1.管理寫請(qǐng)求

          跟隨者

            1.響應(yīng)客戶端的讀請(qǐng)求

            2.負(fù)責(zé)把客戶端提交的寫請(qǐng)求轉(zhuǎn)發(fā)給領(lǐng)導(dǎo)者

           

          znode的觀察機(jī)制

           

          znode以某種方式發(fā)生變化時(shí),“觀察”(watch)機(jī)制可以讓客戶端得到通知。可以針對(duì)ZooKeeper服務(wù)的“操作”來設(shè)置觀察,該服務(wù)的其他操作可以觸發(fā)觀察。比如,客戶端可以對(duì)某個(gè)客戶端調(diào)用exists操作,同時(shí)在它上面設(shè)置一個(gè)觀察,如果此時(shí)這個(gè)znode不存在,則exists返回false,如果一段時(shí)間之后,這個(gè)znode被其他客戶端創(chuàng)建,則這個(gè)觀察會(huì)被觸發(fā),之前的那個(gè)客戶端就會(huì)得到通知。

          sync: 將客戶端的znode視圖與ZooKeeper同步
          SYNC消息:返回SYNC結(jié)果到客戶端,這個(gè)消息最初由客戶端發(fā)起,用來強(qiáng)制得到最新的更新。

          跨客戶端視圖的并發(fā)一致性:

          ZooKeeper并不保證在某時(shí)刻,兩個(gè)不同的客戶端具有一致的數(shù)據(jù)視圖。因?yàn)榫W(wǎng)絡(luò)延遲的原因,一個(gè)客戶端可能在另一個(gè)客戶端得到修改通知之前進(jìn)行更新。假定有兩個(gè)客戶端AB。如果客戶端A將一個(gè)節(jié)點(diǎn)/a的值從0修改為1,然后通知客戶端B讀取/a,客戶端B讀取到的值可能還是0,這取決于它連接到了哪個(gè)服務(wù)器。如果客戶端AB讀取到相同的值很重要,那么客戶端B應(yīng)該在執(zhí)行讀取之前調(diào)用sync()方法。

          所以,ZooKeeper本身不保證修改在多個(gè)服務(wù)器間同步地發(fā)生,但是可以使用ZooKeeper原語來構(gòu)建高層功能,提供有用的客戶端同步。



           設(shè)計(jì)目的
          1.最終一致性:client不論連接到哪個(gè)Server,展示給它都是同一個(gè)視圖,這是zookeeper最重要的性能。
          2 .可靠性:具有簡單、健壯、良好的性能,如果消息m被到一臺(tái)服務(wù)器接受,那么它將被所有的服務(wù)器接受。
          3 .實(shí)時(shí)性:Zookeeper保證客戶端將在一個(gè)時(shí)間間隔范圍內(nèi)獲得服務(wù)器的更新信息,或者服務(wù)器失效的信息。但由于網(wǎng)絡(luò)延時(shí)等原因,Zookeeper不能保證兩個(gè)客戶端能同時(shí)得到剛更新的數(shù)據(jù),如果需要最新數(shù)據(jù),應(yīng)該在讀數(shù)據(jù)之前調(diào)用sync()接口。
          4 .等待無關(guān)(wait-free):慢的或者失效的client不得干預(yù)快速的client的請(qǐng)求,使得每個(gè)client都能有效的等待。
          5.原子性:更新只能成功或者失敗,沒有中間狀態(tài)。
          6 .順序性:包括全局有序和偏序兩種:全局有序是指如果在一臺(tái)服務(wù)器上消息a在消息b前發(fā)布,則在所有Server上消息a都將在消息b前被發(fā)布;偏序是指如果一個(gè)消息b在消息a后被同一個(gè)發(fā)送者發(fā)布,a必將排在b前面。


          節(jié)點(diǎn)宕機(jī):

          應(yīng)用集群中,我們常常需要讓每一個(gè)機(jī)器知道集群中(或依賴的其他某一個(gè)集群)哪些機(jī)器是活著的,并且在集群機(jī)器因?yàn)殄礄C(jī),網(wǎng)絡(luò)斷鏈等原因能夠不在人工介入的情況下迅速通知到每一個(gè)機(jī)器。
          Zookeeper同樣很容易實(shí)現(xiàn)這個(gè)功能,比如我在zookeeper服務(wù)器端有一個(gè)znode叫/APP1SERVERS,那么集群中每一個(gè)機(jī)器啟動(dòng)的時(shí)候都去這個(gè)節(jié)點(diǎn)下創(chuàng)建一個(gè)EPHEMERAL類型的節(jié)點(diǎn),比如server1創(chuàng)建/APP1SERVERS/SERVER1(可以使用ip,保證不重復(fù)),server2創(chuàng)建/APP1SERVERS/SERVER2,然后SERVER1和SERVER2都watch /APP1SERVERS這個(gè)父節(jié)點(diǎn),那么也就是這個(gè)父節(jié)點(diǎn)下數(shù)據(jù)或者子節(jié)點(diǎn)變化都會(huì)通知對(duì)該節(jié)點(diǎn)進(jìn)行watch的客戶端。因?yàn)镋PHEMERAL類型節(jié)點(diǎn)有一個(gè)很重要的特性,就是客戶端和服務(wù)器端連接斷掉或者session過期就會(huì)使節(jié)點(diǎn)消失,那么在某一個(gè)機(jī)器掛掉或者斷鏈的時(shí)候,其對(duì)應(yīng)的節(jié)點(diǎn)就會(huì)消失,然后集群中所有對(duì)/APP1SERVERS進(jìn)行watch的客戶端都會(huì)收到通知,然后取得最新列表即可。


          zookeeper是一個(gè)高可用性,高性能的協(xié)調(diào)服務(wù)
          解決哪些問題
          在分布式應(yīng)用中,經(jīng)常會(huì)出現(xiàn)部分失敗的情況,即當(dāng)節(jié)點(diǎn)間傳遞消息的時(shí)候由于網(wǎng)絡(luò)或者接收者進(jìn)程死掉等原因,發(fā)送者無法知道接收者是否收到消息。
          由于部分失敗是分布式系統(tǒng)固有的特征因此zookeeper并不能避免部分失敗,但是它可以幫你在部分失敗的時(shí)候進(jìn)行正確處理
          為了解決這個(gè)問題zookeeper具有以下特征:
          1:zookeeper提供豐富的構(gòu)件(building block)來實(shí)現(xiàn)很多協(xié)調(diào)數(shù)據(jù)結(jié)構(gòu)和協(xié)議
          2:訪問原子性,客戶端要么讀到所有數(shù)據(jù),要么讀取失敗,不會(huì)出現(xiàn)只讀取部分的情況
          3:zookeeper運(yùn)行在一組機(jī)器上,具有高可用性,幫助系統(tǒng)避免單點(diǎn)故障,同時(shí)刪掉故障服務(wù)器
          4:順序一致性:任意客戶端的更新請(qǐng)求會(huì)被按照發(fā)送順序提交
          5:單一系統(tǒng)映像:當(dāng)一臺(tái)服務(wù)器故障,導(dǎo)致它的客戶端需要連接其它服務(wù)器的時(shí)候,所有更新晚于故障服務(wù)器的服務(wù)器都不會(huì)接收請(qǐng)求,一直到更新趕上故障服務(wù)器
          6:及時(shí)性:任何客戶端能看到的滯后都是有限的,不會(huì)超過幾十秒,且提供sync操作強(qiáng)制客戶端所連的服務(wù)器與領(lǐng)導(dǎo)者同步
          7:會(huì)話:每個(gè)客戶端連接時(shí)會(huì)嘗試連接到配置列表中的一臺(tái)服務(wù)器,一旦失敗會(huì)自動(dòng)連接另一臺(tái)服務(wù)器依次類推,知道成功連接一臺(tái)服務(wù)器,從而創(chuàng)建一個(gè)會(huì)話,客戶端可以位每個(gè)會(huì)話設(shè)置超時(shí)時(shí)間,一旦會(huì)話過期,則所有短暫znode會(huì)丟失,因?yàn)閦ookeeper會(huì)自動(dòng)發(fā)送心跳包,所以很少發(fā)生
          8:約會(huì)機(jī)制(rendezvous),在交互的過程中,被協(xié)調(diào)的各方不許要事先彼此了解,甚至不必同時(shí)存在
          9:ACL:zookeeper提供了digest(通過用戶名密碼),host(通過主機(jī)名),ip(通過ip地址)3種身份驗(yàn)證模式,依賴與zookeeper的身份驗(yàn)證機(jī)制每個(gè)ACL都是一個(gè)身份對(duì)應(yīng)一組權(quán)限,如果我們要給demo.com的客戶端域一個(gè)讀權(quán)限在java語言中可以這樣創(chuàng)建:
          new ACL(Perms.READ, new Id("host", "demo.com"));
          Ids.OPEN_ACL_UNSAFE是將所有ADMIN之外的權(quán)限授予每個(gè)人
          另zookeeper還可以集成第三方的身份驗(yàn)證系統(tǒng)
          10:提供關(guān)于通用協(xié)調(diào)模式的開源共享資源庫
          11:高性能的(官方數(shù)據(jù))對(duì)以寫為主的工作負(fù)載來說使用5臺(tái)不錯(cuò)的機(jī)器基準(zhǔn)吞吐量達(dá)到10000+




          posted @ 2015-05-08 22:10 abin 閱讀(650) | 評(píng)論 (0)編輯 收藏

          各種設(shè)計(jì)模式--應(yīng)用場(chǎng)景:
          裝飾器模式:
          1、類繼承會(huì)導(dǎo)致類的膨脹,這時(shí)候裝飾器就派上用場(chǎng)了
          責(zé)任鏈模式:
          1、ifelse 用責(zé)任鏈來實(shí)現(xiàn)
          狀態(tài)模式:
          1、ifelse
          適配器模式:目的是在原來代碼的基礎(chǔ)上面,增加一些修飾的東西。
          1、訂單信息,比如增加了活動(dòng)了之后,返回結(jié)果中要包含活動(dòng)信息,在原來代碼的基礎(chǔ)上面給返回的Bean里面增加一些活動(dòng)信息。
          代理模式:
           比如吧,我有一個(gè)業(yè)務(wù),同時(shí)要調(diào)用外部系統(tǒng)的http實(shí)現(xiàn)的接口和webservice實(shí)現(xiàn)的接口,可以做一個(gè)代理類, 代理webservice接口和http接口, 代理類幫我判斷該用哪個(gè), 我直接調(diào)用代理類就行了。代理類專門屏蔽后面的接口或者協(xié)議。
          模板方法模式:
          1、比如訂單的下單還有退款操作,都需要同時(shí)判斷使用的金額和紅包。
          2、支付的時(shí)候,調(diào)用不同的支付方式,都需要去做判斷。
          策略模式:





          策略模式和裝飾器模式區(qū)別:
          策略模式偏向于對(duì)實(shí)現(xiàn)方法或策略的封裝,調(diào)用者不需要考慮具體實(shí)現(xiàn),只要指定使用的策略即可。
          裝飾器模式一般用于需要對(duì)功能進(jìn)行擴(kuò)展的場(chǎng)合,每一種裝飾都是一種擴(kuò)展或增強(qiáng)。

          看起來兩個(gè)模式好像沒有必然的聯(lián)系,但是在實(shí)際使用過程中,發(fā)現(xiàn)了一個(gè)讓我困惑的地方。
          先看一個(gè)典型的場(chǎng)景:
                      商場(chǎng)對(duì)客戶打折,老客戶8折,新客戶9折,新客戶購物滿3000,打8.5折
          對(duì)這個(gè)基本場(chǎng)景,一般給的經(jīng)典模式是策略模式,很多書也以這個(gè)作為策略模式的的經(jīng)典案例。
          但是,如果我把每一種折扣看作是一種對(duì)原有價(jià)格的裝飾,這個(gè)場(chǎng)景也是可以用裝飾器模式實(shí)現(xiàn)的。
          兩個(gè)模式都需要花費(fèi)一些代碼去判斷策略或裝飾器的類型,而且實(shí)現(xiàn)難度也旗鼓相當(dāng)。

          我用兩種模式都實(shí)現(xiàn)了相同的功能,但是卻沒有發(fā)現(xiàn)明顯的區(qū)別,不知道大家對(duì)這兩個(gè)模式怎么看,
          歡迎討論。


          策略模式更傾向是N選1的模式,也即根據(jù)條件選擇相應(yīng)的算法,但各種算法是互斥的,比如:團(tuán)體客戶和個(gè)人客戶的優(yōu)惠政策必然是非此即彼的;

          裝飾模式是在主體邏輯的基礎(chǔ)上的附加邏輯,比如,個(gè)人客戶有的屬于同城客戶,支持送貨上門。

          謝謝您的回復(fù),如果按照策略模式,每一種打折方案是一種策略,而且只能選擇一個(gè),這是沒有問題的。
          按照裝飾模式,每一種折扣都是在購買金額上的附加,在沒有折上折或者送貨上門這些附加值的時(shí)候,我感覺裝飾模式也是實(shí)用的,當(dāng)然,當(dāng)折上折和送貨這種附加體現(xiàn)的時(shí)候,裝飾起的模式就體現(xiàn)去來了。

          所以,我感覺在當(dāng)前描述的問題中,這兩個(gè)模式應(yīng)該都可以很恰當(dāng)?shù)膶?shí)現(xiàn)需求,但是沒感覺到本質(zhì)的區(qū)別。
          于是就有些困惑了,看了您的總結(jié),我感覺自己有點(diǎn)鉆牛角了。
          如果這個(gè)場(chǎng)景新增附加需求,比如新增vip客戶,那么策略模式就比較合適了。
          但是如果進(jìn)行折上折或者送貨上門這類附加需求,很明顯裝飾模式會(huì)更好一些了。
          看來具體的模式還得根據(jù)實(shí)際需求確定,不能死搬硬套。
          盡管樓主可以使用兩種模式實(shí)現(xiàn)自己說的場(chǎng)景,但是兩者還是有本質(zhì)的區(qū)別。

          策略模式,已經(jīng)說的很清楚, 就不多說了。

          裝飾模式是主題邏輯的基礎(chǔ)上的加強(qiáng)。可以看看JAVA IO的設(shè)計(jì)。
          就像樓上說的, 如果客戶購買滿5000, 不只可以享受7折優(yōu)惠, 還可以送貨上門。
          這里有兩項(xiàng)功能: 1) 7折優(yōu)惠, 2)送貨上門
          如果使用策略模式, 我們勢(shì)必把兩項(xiàng)功能都寫在一個(gè)策略的實(shí)現(xiàn)類里面。
          假使現(xiàn)在有新的場(chǎng)景出現(xiàn),就是老客戶購買滿3000, 也享受送貨上門。(或者說這里面的還蘊(yùn)藏一些其他的優(yōu)惠,比如說返券等等)
          難道我們又把這些功能添加到我們的策略里面, 這樣代碼就很生硬而且不容易修改。

          但是使用裝飾模式就不一樣,裝飾模式能動(dòng)態(tài)的給對(duì)象增加特有的功能。 比如說IO里面可以添加Buffer的功能。 同樣在我們的場(chǎng)景里面,我們也可以將送貨上門、返券等也動(dòng)態(tài)的增強(qiáng), new 送貨上門(new 返券())...., 這樣子就很靈活了。

          策略實(shí)現(xiàn)可能類似:
          do7折();
          do送貨上門();
          do返券()

          裝飾的實(shí)現(xiàn)可能了類似:
          new 7折( new 送貨上門(new 返券())), 能隨意組合;

          所有的優(yōu)惠都享受上了, 看上去還是爽一點(diǎn)。 

          其實(shí)裝飾模式, 還是更符合設(shè)計(jì)的一條原則: 少繼承, 多組合 
          posted @ 2015-05-08 17:32 abin 閱讀(494) | 評(píng)論 (0)編輯 收藏

          僅列出標(biāo)題
          共50頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
          主站蜘蛛池模板: 曲沃县| 尉氏县| 澜沧| 且末县| 湟源县| 东海县| 本溪| 长乐市| 壤塘县| 江陵县| 台东县| 塔城市| 孟州市| 卢氏县| 凤阳县| 竹北市| 星座| 东乡族自治县| 龙山县| 天峨县| 东辽县| 黄梅县| 肃宁县| 茂名市| 抚宁县| 商洛市| 台前县| 弥勒县| 肇州县| 桃江县| 水城县| 曲阳县| 金溪县| 揭东县| 广水市| 嵊泗县| 益阳市| 瓦房店市| 新密市| 绩溪县| 阳原县|