• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            We do not always find visible happiness in proportion to visible virtue

            夢幻白樺林

            SHARE

              C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              14 Posts :: 58 Stories :: 62 Comments :: 0 Trackbacks

            公告

            常用鏈接

            留言簿(5)

            搜索

            •  

            最新隨筆

            最新評論

            閱讀排行榜

            2009年4月25日 #

                .net 中Unit已經(jīng)標(biāo)記了Serializable了
              [Serializable]
                [TypeConverter(
            typeof(UnitConverter))]
                
            public struct Unit
                {
            }

            我定義了個(gè)類,其中有個(gè)width屬性

                    Unit width;

                    [DefaultValue(
            typeof(Unit), "")]
                    [Bindable(
            true)]
                    [Description(
            "列寬")]
                    
            public Unit Width
                    {
                        
            get { return width; }
                        
            set { width = value; }
                    }
            序列化后為<Width/>
            posted @ 2009-04-25 17:00 colys 閱讀(1518) | 評論 (3)編輯 收藏

            從字符串中取出包含的函數(shù)名和所有參數(shù)你這樣:[method("arg1",arg2,...n個(gè))]

            要求:

            以[開頭,]結(jié)尾

            method 為 sum , count ,page, eval  其中的一個(gè)

            可以沒有括號(hào),比如[page]

            參數(shù)可以有引號(hào),也可以沒有引號(hào),參數(shù)不限個(gè)數(shù),比如:
            [sum("Money")]    要能取出 sum, Money
            [count(0)]   要能取出 count, 0
            [eval("aa",1)] 要能取出 eval aa,1

            posted @ 2009-04-25 15:56 colys 閱讀(2162) | 評論 (6)編輯 收藏

            2007年11月21日 #

            福鼎白茶
            白茶屬微發(fā)酵茶,是我國六大類茶葉中的一顆璀璨明珠,中國是白茶的惟一產(chǎn)地。白茶的品質(zhì)特征為:成茶披滿白毫,十分素雅,湯色清淡,味鮮醇、清甜、有毫香。基本加工工藝流程是萎調(diào)、曬干或低溫烘干。因采用鮮葉原料不同,故可分為:白毫銀針、白牡丹、貢眉、壽眉及新工藝白茶五種。生產(chǎn)白茶對品種和加工工芤要求十分嚴(yán)格,適制白茶的茶樹品種為:福鼎大白茶、福鼎大毫茶、政和大白茶和閩北水仙等。白茶是我國歷史名茶,其主產(chǎn)區(qū)在福建省福鼎市、政和縣,建陽、建甌等縣市也有少量生產(chǎn)。據(jù)茶葉史料記載,白茶首創(chuàng)于福建省福鼎縣,又據(jù)福建省地方志編委會(huì)出版的《福建地方志》和現(xiàn)代茶葉著名專家張?zhí)旄=淌诘摹陡=ò撞璧恼{(diào)查研究》及清代明人周亮工《閩小記》的記載,清喜慶初年(公元1796年),福鼎人用菜茶(有性群體種)的壯芽為原料,創(chuàng)制白毫銀針。在1857年,福鼎大白茶茶樹品種從太姥山移植到福鼎縣點(diǎn)頭、柏柳等地選育成功,由于福鼎大白茶芽壯、毫顯、香高,所制白毫銀針外型品質(zhì)遠(yuǎn)遠(yuǎn)優(yōu)于“菜茶”。于是福鼎茶人改用福鼎大白茶的壯芽為原料制造“白毫銀針”,出口價(jià)高于原菜茶加工的銀針(后來稱土針)10多倍。約在1860年,“土針”逐漸退出“白毫銀針”的歷史舞臺(tái)。據(jù)《福建地方志》記載,政和縣1880年選育繁殖成功“政和大白茶”品種,1889年開始產(chǎn)制銀針。兩地生產(chǎn)銀針時(shí)間相距約80多年。總之,白茶類中是先有“銀針”,后才有白牡丹、貢眉、壽眉,至于新工藝白牡丹,是二十世紀(jì)70年代由原福鼎茶廠白琳分廠研制的一個(gè)新的白茶產(chǎn)品。所以說,白茶之所以能自成一類,是因其具有獨(dú)特的產(chǎn)地(區(qū)域)、獨(dú)特的品種和獨(dú)特的加工工藝,離開其中任何一個(gè)因素都生產(chǎn)不出好茶。同時(shí),生產(chǎn)白茶具有很大的風(fēng)險(xiǎn)性,表面上看加工工藝二十簡單,但其內(nèi)在的技術(shù)要領(lǐng)二十不易掌握。

            天山綠茶

            天山綠茶是福建省的歷史名茶,為閩東烘青綠茶的極品。品質(zhì)特優(yōu),尤其是里、中、外天山所產(chǎn)的綠茶品質(zhì)更佳,稱之“正天山綠茶”。
            據(jù)《寧德縣志》記載,天山綠茶曾經(jīng)歷一段變革演化過程。宋代生產(chǎn)團(tuán)茶、餅茶,也生產(chǎn)乳茶、龍團(tuán)茶。到了元、明代生產(chǎn)“茶餅”,供作禮品和祭祀品。公元1781年前后,天山所產(chǎn)的芽茶已被列為貢品。明、清以后,以生產(chǎn)炒青條形茶為主。幾經(jīng)變革,到了1979年,才改制為烘青型綠茶,成為高檔花茶的優(yōu)質(zhì)原料。歷史上,天山綠茶花色品種豐富多彩,而今,除少數(shù)花色品種失傳外,大多數(shù)傳統(tǒng)花色品種,如天山雀舌、鳳眉、明前、清明等均得到恢復(fù),并創(chuàng)制了新的品種,如清水綠、天山毛峰、天山銀毫、四季春、毛尖等。這些綠茶以鋒苗挺秀、香高、味濃、色翠、耐泡五大特點(diǎn)贏得了榮譽(yù)。從1979年恢復(fù)生產(chǎn)以來,曾多次在地、省及全國名茶評選會(huì)上獲獎(jiǎng),名列前茅。天山銀毫茉莉花茶在全國內(nèi)銷花茶評比會(huì)上,名列第一。1982年、1986年二次被評為全國名茶,商業(yè)部授于全國名茶榮譽(yù)證書。
            天山位于東海之濱,天山主峰——屏南天湖山,屹立在福建省屏南、寧德、古田三縣交界的屏南黛溪鄉(xiāng)。除天湖山外,還有天峰山、仙峰山、大坪山等山脈,是天山綠茶的原產(chǎn)地。這里山峰險(xiǎn)峻,海拔1300米左右,林木參天,云海翻滾,氣候溫和,年均氣溫15℃左右,年降雨量1900毫米左右,土壤肥沃濕潤,多為結(jié)構(gòu)疏松的砂質(zhì)壤土。茶樹多生長在巖間和山坡上,樹壯芽肥,是適制天山綠茶的理想原料。難怪詩人贊道:“深山奇石嵯峨立,峽谷懸崖味茶香”。
            天山綠茶采用的原料因花色品種不同而異。如雀舌和鳳眉等傳統(tǒng)珍品,選用葉質(zhì)肥厚、持嫩性強(qiáng)的天山菜茶品種的芽葉為原料。采摘標(biāo)準(zhǔn)為一芽一葉和一芽二葉初展。制500克干茶約需3萬個(gè)左右芽葉。新創(chuàng)制的名茶如清水綠等,則選取大、中葉種的芽葉為原料,采摘標(biāo)準(zhǔn)以一芽二葉初展為主,制500克干茶需7000個(gè)左右芽葉。
            天山綠茶實(shí)現(xiàn)了機(jī)械化生產(chǎn)。主要設(shè)備有連續(xù)滾筒電熱恒溫殺青機(jī),40型或45型揉捻機(jī),自動(dòng)百葉烘干機(jī)等。加工工藝有涼青、殺青、揉捻、烘干(毛火和足火)四道工序。殺青掌握“高溫、控?zé)帷⑸倭俊⒍虝r(shí)”的方法。筒溫240~260℃,電熱控制,前高后低。起鍋攤涼散熱后再行揉捻。揉捻時(shí)采用“小機(jī)、適量、輕壓、短揉”的技術(shù)措施,達(dá)到條索緊結(jié)、色澤翠綠、香味清鮮的目的。40型揉捻機(jī)投葉量7.5~10公斤,45型揉捻機(jī)投葉量10~12.5公斤。轉(zhuǎn)速55轉(zhuǎn)C分。烘干毛火掌握“薄攤、高溫、快烘”的原則。足火掌握低溫慢烘,達(dá)到干度內(nèi)外均勻一致,香高而鮮爽的目的。毛火烘溫115℃左右,含水量15~20%。足火烘濕90~95℃,含水量6%左右。
            天山綠茶具有“三綠”特色,即色澤翠綠,湯色碧綠,葉底嫩綠,且外形條索嫩勻、鋒苗挺秀、茸毫顯露,香似珠蘭花香,芬芳鮮爽,滋味濃厚回甘,猶如新鮮橄欖,湯色清澈明亮,經(jīng)泡耐飲,沖泡3~4次,茶味猶存。飲之幽香四溢,齒頰留芳,令人心曠神怡

            福鼎白琳工夫茶
            "白琳工夫茶"充分發(fā)揮福鼎大白茶的特點(diǎn),精選細(xì)嫩芽葉,制成工夫茶,外形條索緊結(jié)纖秀,含有大量的橙黃白毫,具有鮮爽愉快的毫香,湯色、葉底艷麗紅亮,取名為「桔紅」,意為桔子般紅艷的工夫,風(fēng)格獨(dú)特,在國際市場上很受歡迎。
            "白琳工夫茶"系小葉種紅茶,當(dāng)?shù)胤N植的小葉群體種具有茸毛多、萌芽早、產(chǎn)量高的特點(diǎn),一般的白琳工夫,外形條索細(xì)長彎曲,茸毫多呈顆粒絨球狀,色澤黃黑,內(nèi)質(zhì)湯色淺亮,香氣鮮純有毫香,味清鮮甜和,葉底鮮紅帶黃。
            "白琳工夫"為三大閩紅工夫之一,以其獨(dú)特風(fēng)格和品質(zhì)盛興百年而不衰。白琳功夫茶采用福鼎大白茶代替原有的小葉種,成為加工白琳功夫的主要原料,使其質(zhì)量有了顯著的提高。它的品質(zhì)特征,幾乎代表白琳功夫高級(jí)茶的獨(dú)特風(fēng)格,在國際市場上很受歡迎。主要特點(diǎn)是:條索緊結(jié),茶毫顯露金黃色,干茶色澤烏潤油亮,湯色紅艷明亮,葉底紅亮,滋味鮮濃醇爽,香氣清高,有特殊的花香,耐沖泡,既適合清飲,又適合摻和砂糖、牛奶。

            福鼎蓮心茶
            蓮心茶形似蓮子瓣心而得名,為我國傳統(tǒng)名茶。產(chǎn)于福建省太姥山麓的福鼎百琳和霞浦水門。太姥山景色秀麗,崖林之間茶樹叢主。相傳,早在光緒年間,太姥山麓的白琳一帶,茶樹已廣為種植。到了本世紀(jì)30年代,蓮心茶以茶中珍品聞名海內(nèi)外。用蓮心茶窨制成茉莉娥眉、茉莉秀眉,為花茶中的佼佼者,深受東南亞僑胞的喜愛。

            蓮心茶采取福鼎大白茶的一芽二葉為原料。經(jīng)萎凋、殺青、揉捻、干燥等四道工序加工而成。

            萎凋:目的在于蒸發(fā)部分水分,促使芽葉內(nèi)含物發(fā)生適度的變化,消除成品的苦澀味。當(dāng)?shù)氐慕?jīng)驗(yàn)是萎凋應(yīng)掌握適當(dāng)?shù)南薅龋虺潭冗^輕達(dá)不到萎凋的目的;萎凋程度過重,即失水過多,內(nèi)含物質(zhì)變化過大,均不利蓮心茶品質(zhì)的形成。通常,芽葉減重率控制在18%左右,時(shí)間6~8小時(shí)。當(dāng)葉色轉(zhuǎn)為暗綠,葉的側(cè)脈折而不斷,折梗尚能脆斷,葉質(zhì)柔軟,即為適度。

            殺青:手工殺青,全用抖炒。做到抖得散,翻得勻。殺青鍋溫180℃左右,投葉量1500克左右,當(dāng)葉子松散不粘手,清香透露即為適度。

            揉捻:殺青葉經(jīng)攤涼冷卻后進(jìn)行揉捻。達(dá)到茶索挺直緊結(jié)的目的。

            干燥分毛火和足火兩個(gè)過程。毛火在烘籠上進(jìn)行,烘溫90~100℃,每籠投葉量1500克左右,烘至七、八成干為適度。足火在炒鍋內(nèi)進(jìn)行,鍋溫80℃左右,炒至足干,色略顯灰為適。

            蓮心茶的品質(zhì)特點(diǎn)是,外形細(xì)緊纖秀,鋒苗顯露,色澤綠中帶黃,有似蓮子蕊色,香氣清幽,含綠豆清香,味醇鮮爽,湯色橙綠清澈,葉底嫩勻成朵。泡在杯中,兩葉相對而開,中間豎一芽心,猶如蓮子瓣心,頗有情趣。

            福安坦洋工夫紅茶
              坦洋工夫分布較廣,主產(chǎn)福安、柘榮、壽寧、周寧、霞浦及屏南北部等地。坦洋工夫源于福安境內(nèi)白云山麓的坦洋村,相傳清咸豐、同治年間(公元1851 --1874年),坦洋村有胡福四(又名胡進(jìn)四)者,試制紅茶成功,經(jīng)廣州運(yùn)銷西歐。很受歡迎,此后茶商紛紛入山求市,接踵而來并設(shè)洋行,周圍各縣茶葉亦漸云集坦洋.坦洋工夫名聲也就不脛而走,自光緒六年 至民國二十五年(公元1881—1936年)的50余年, 坦洋工夫每年出口均上萬擔(dān),其中1898年出口3萬余組。

              坦洋街長一公里,設(shè)茶行達(dá)36家,雇工3000余人,產(chǎn)量2萬余擔(dān)。收條范圍上至政和縣的新村,下至霞浦縣的赤嶺,方圓數(shù)百里,境跨七、八個(gè)縣,成為福安的主要紅茶產(chǎn)區(qū)。運(yùn)銷荷蘭、英國、日本、東南亞等二十余個(gè)國家與地區(qū),每年收外匯茶銀百余萬元。當(dāng)時(shí)民諺云:“國家大興,茶換黃金,船泊龍鳳橋, 白銀用斗量。”后因抗日戰(zhàn)爭爆發(fā),銷路受阻,生產(chǎn)亦遭嚴(yán)重破壞,坦洋工夫產(chǎn)量銳減。

              50年代中期,為了恢復(fù)和提高坦洋工夫紅茶的產(chǎn)量和品質(zhì),先后建立了國營坦洋、水門紅茶初制廠和福安茶廠,實(shí)行機(jī)械化制茶,引進(jìn)并繁殖福鼎大白茶、福安大白茶、福云等優(yōu)良茶樹品種,1960年產(chǎn)量增加到5萬擔(dān),創(chuàng)歷史最高水平。后因茶類布局的變更,由“紅”改“綠”,坦洋工夫尚存無幾。近年來,經(jīng)有關(guān)部門的努力,坦洋工夫又有所恢復(fù)和發(fā)展,1988年產(chǎn)量達(dá)8000余擔(dān)。

              坦洋工夫外形細(xì)長勻整,帶白毫,色澤烏黑有光,內(nèi)質(zhì)香味清鮮甜和,湯鮮艷呈金黃色,葉底紅勻光滑。其中坦洋、壽寧、周寧山區(qū)所產(chǎn)工夫茶,香味醇厚,條索較為肥壯,東南臨海的霞浦一帶所產(chǎn)工夫茶 色鮮亮,條形秀麗。
            posted @ 2007-11-21 21:47 colys 閱讀(1466) | 評論 (1)編輯 收藏

            2007年10月8日 #

            #1  Web 2.0 編程思想:16條法則

            原文:Thinking in Web 2.0: Sixteen Ways
            作者:Dion Hinchcliffe
            URL:http://sd.csdn.net/n/20060518/90603.html

            1、在你開始之前,先定一個(gè)簡單的目標(biāo)。無論你是一個(gè)Web 2.0應(yīng)用的創(chuàng)建者還是用戶,請清晰的構(gòu)思你的目標(biāo)。就像“我需要保存一個(gè)書簽”或者“我準(zhǔn)備幫助人們創(chuàng)建可編輯的、共享的頁面”這樣的目標(biāo),讓你保持最基礎(chǔ)的需求。很多Web 2.0應(yīng)用的最初吸引之處就是它的簡單,避免并隱藏了那些多余的復(fù)雜性。站在創(chuàng)建者的立場,可以想象Google的幾乎沒有內(nèi)容的主頁,還有del.icio.us的簡單的線條。從最終用戶的角度來看,與之齊名的就是Diggdot.us所提供的初始化頁面。你能夠并且希望加入更多功能,但是先做好最開始的。在一個(gè)時(shí)候只做一個(gè)特性,完成一個(gè)目標(biāo)。這聽起來很太過于單純化了,但它將使你更加專注,而且你也會(huì)明白我的意思。

            2、鏈接是最基礎(chǔ)的思想。這就是我們稱之為Web的一個(gè)理由。鏈接是把Web中各種實(shí)體連接起來的最基本的元素。你的信息、你的關(guān)系、你的導(dǎo)航,甚至是能夠被寫成URL的任何內(nèi)容。這里有一個(gè)鏈接應(yīng)該遵循的規(guī)則(其實(shí)你也不必嚴(yán)格的遵守):

            ??? 1. Web上的任何東西都是可以被URI或者是URL所連接的。
            ??? 2. 把所有的鏈接都保存為他的原始出處,這樣可以讓你與任何人、在任何地方、任何時(shí)候都能分享它。
            ??? 3. 第二條中任何時(shí)候的前提是鏈接必須是持久的,它不會(huì)在沒有任何緣由的情況下被改變或者是消失。
            ??? 4. 鏈接應(yīng)該是人類可讀的、穩(wěn)定的、并且能夠自我詮釋的。

            3、數(shù)據(jù)應(yīng)該屬于創(chuàng)建它的人。是的,你聽我的。任何用戶創(chuàng)建的、貢獻(xiàn)的或分享的都是他們自己的,除非他們很明顯的放棄這個(gè)權(quán)力來讓你自由處置。他們貢獻(xiàn)到Web上的任何信息都應(yīng)該是可編輯的、能被刪除的、并且能夠取消共享,無論在任何時(shí)候,只要用戶愿意。這也包含了那些間接的數(shù)據(jù),像他們所關(guān)心的記錄、日志、瀏覽歷史、網(wǎng)站訪問信息,或者是任何可以被跟蹤的信息。所有的網(wǎng)站必須清晰簡單的陳訴那些信息是用戶創(chuàng)建的,并且提供他們停止創(chuàng)建的方法,甚至是清除的方法。

            4、數(shù)據(jù)優(yōu)先,體驗(yàn)與功能其次。無論它是文本、圖片、音頻還是視頻,Web最終還是把這些解析為數(shù)據(jù)。換句話說,你無法脫離數(shù)據(jù)去呈現(xiàn)內(nèi)容。所有這些數(shù)據(jù)都通過那些易于發(fā)現(xiàn)的URL來定位(參見第2條)。通過另一種形式來看待這些,Web最終是名詞優(yōu)先,動(dòng)詞其次,雖然最近正在向動(dòng)詞偏移。來看看名詞的例子:日歷的條目、家庭照片、股票價(jià)格。還有一些動(dòng)詞的例子:定一個(gè)約會(huì)、共享一張圖片、買一份股票。

            5、做好積極分享一切的準(zhǔn)備。盡可能的分享一切,你所擁有的所有數(shù)據(jù),你所提供的所有服務(wù)。鼓勵(lì)不遵循原有意圖的使用,提倡貢獻(xiàn),不要那些需要分享的內(nèi)容堅(jiān)持設(shè)置為私有的。在分享與發(fā)現(xiàn)之后,提供易于使用的瀏覽方式是顯而易見的需求。為什么呢:話說回來,你會(huì)從別人的共享之中受益匪淺。注意:這里沒有許可讓你去侵犯版權(quán)保護(hù)的法律,你不能夠去分享你刻錄的DVD或者是擁有商業(yè)版權(quán)音樂,因?yàn)槟阋呀?jīng)同意不會(huì)去分享這些東西。但是你可以發(fā)現(xiàn)并分享那些完全開放的媒體內(nèi)容。一個(gè)小小的建議,你可以學(xué)習(xí)一下Creative Commons license(共創(chuàng)協(xié)議).

            6、Web是一個(gè)平臺(tái);要讓它成長。當(dāng)然,我們還有很多其他的平臺(tái)(Windows、Linux、Mac),但是那些已經(jīng)不是重點(diǎn)了。換句話說,Web是無法脫離的平臺(tái),不會(huì)中斷的平臺(tái),你可以通過各種方式去擴(kuò)展的平臺(tái)。你在Web上提供的數(shù)據(jù)與服務(wù)將會(huì)成為Web一部分,最終你會(huì)在Web平臺(tái)的某一處扮演你的角色。扮演好你的角色并照顧好后來者。

            7、理解與信奉“階梯性”。現(xiàn)在的Web越來越大,幾乎蔓延到了全世界的所有國家,并且已經(jīng)擁有了10億用戶。我的觀點(diǎn)是Web的各個(gè)組成部分存在著細(xì)微的區(qū)別和不同,就像不同地方的用戶那樣。例如Web的設(shè)計(jì)部分:易用性永遠(yuǎn)優(yōu)先于速度、可靠性、重用性與可集成性。你也應(yīng)該提供同樣的體驗(yàn)給你的用戶。它已經(jīng)被一次又一次的被人們在文檔中強(qiáng)調(diào),忠誠的用戶很快會(huì)成為專業(yè)的用戶,他們期待更快的速度還有更多。退一步支持他們。同樣,也有很多很多的用戶會(huì)進(jìn)入這個(gè)階梯的底端,如你所期待的那樣。他們可能不會(huì)說你的語言,不熟悉你的文化,甚至不知道是如何到這里的。所以你需要向他們表達(dá)清楚。

            8、任何東西都是可編輯的。或者是它應(yīng)該被編織的更好。要確定的是,只有很少的東西是不能被編輯的,剩下的都可以,這是一個(gè)可寫的Web。這并不意味著原始內(nèi)容的丟失,而通常被理解為用戶能夠很容易的對內(nèi)容加以評論,或者評注內(nèi)容是在那里發(fā)現(xiàn)的。如果你對此應(yīng)用的好,他們能夠比你所想象的做的更多(把內(nèi)容串起來并且給予原始內(nèi)容來創(chuàng)建自己的,等等)。

            9、Web上的身份是神圣的。不幸的是,這并不意味著你能夠得到更多的隱私(這完全是上個(gè)世紀(jì)的想法)。但對身份的驗(yàn)證是必要的,你應(yīng)該感謝那些只需一個(gè)郵件地址就能確定你身份的服務(wù)。這意味只要你對你的用戶承諾了,你就必須保證他們的隱私安全。必要的時(shí)候,在這個(gè)世界的某處你還得為你的用戶挺身而出,向當(dāng)?shù)氐臋?quán)威挑戰(zhàn)。如果你沒有打算那樣做,你就得把實(shí)際情況告訴你的用戶。另一方面,如果身份是必須的,不要試圖偽裝它,不然在某一天我們將會(huì)在Web上放棄我們的最后一點(diǎn)點(diǎn)隱私的權(quán)利。

            10、了解流行的標(biāo)準(zhǔn)并且使用他們。從一個(gè)消費(fèi)者或者是創(chuàng)作者的立場來看,數(shù)據(jù)將會(huì)以不同的格式與任何一個(gè)人交換。同時(shí)這樣的數(shù)據(jù)也會(huì)反過來促進(jìn)標(biāo)準(zhǔn)的完善與采納。這通常意味像RSS、 OPML、XHTML、Simple XML、JSON等簡單標(biāo)準(zhǔn)的流行,而避免SOAP、XSD,還有RDF、ATOM也一樣,使用它們會(huì)給我的內(nèi)心帶來痛苦。請你也為你所鐘愛的標(biāo)準(zhǔn)投上一票來支持它們。

            11、遵循無意使用的規(guī)律。如果你把非常有趣的數(shù)據(jù)和服務(wù)用廣泛使用的格式開放和共享出去,你將會(huì)得到你所應(yīng)得的,其他人也將會(huì)基于你的那一塊Web平臺(tái)來構(gòu)建。或許還會(huì)從別人那里得到更多,所以為這個(gè)做一下準(zhǔn)備比較好。我已記不清有多少次我看到一個(gè)播客(podcasting)服務(wù)因?yàn)榱餍羞^渡而導(dǎo)致服務(wù)垮掉,就是因?yàn)樗麄儽?Slashdot和del.icio.us給收錄了。這一點(diǎn)要知道:網(wǎng)絡(luò)上的大量化意味著如果一個(gè)內(nèi)容非常有趣,即使是一個(gè)很小的角落也會(huì)得到驚人的訪問量。鼓勵(lì)使用這種方式,它還是非常有價(jià)值的,前提是你要有所準(zhǔn)備。

            12、粒化你的數(shù)據(jù)與服務(wù)。我們應(yīng)該在很早以前就明白這些,大規(guī)模集成的數(shù)據(jù)僅僅適用于無需管理的下載與批量操作。分解你的數(shù)據(jù),讓他們獨(dú)立成可描述的URL地址,對你的服務(wù)也一樣。反過來說,你不要?jiǎng)?chuàng)建一些巨大的、復(fù)雜的、像圣誕樹那樣的數(shù)據(jù)結(jié)構(gòu)和服務(wù)。保持簡單,要非常的簡單。讓這些分離的片斷能夠容易的被重組和發(fā)現(xiàn)。

            13、提供用戶能夠單獨(dú)受益的數(shù)據(jù)和服務(wù)。漸漸依賴于這種社會(huì)化參與是存在風(fēng)險(xiǎn)的,你需要讓你的用戶有一點(diǎn)點(diǎn)動(dòng)機(jī)來貢獻(xiàn)時(shí)間、熱情和信息,除非他們能夠直接受益。社會(huì)化分享比個(gè)體行為的利益大很多,除非你能夠激發(fā)用戶的個(gè)人動(dòng)機(jī),否這你將無法享受這份厚禮。

            14、讓用戶組織并過濾信息。不一定是必須的,但卻是非常重要的。讓用戶以他們自己的方式來標(biāo)注和組織數(shù)據(jù),因?yàn)槟阕约菏怯肋h(yuǎn)無法及時(shí)的處理他們的。用戶會(huì)按照他們自己理解的最佳方式來處理并構(gòu)建。要保證你的Web服務(wù)能夠按照用戶所需所想的方式來工作。這也是標(biāo)簽(tagging)和通俗分類(folksonomies )的方式如此成功的主要因素。

            15、提供豐富的用戶體驗(yàn)。Web一直都在和本地的應(yīng)用程序進(jìn)行著激烈的競爭。為什么?因?yàn)楸镜爻绦蜻€是感覺上好一些,速度也快一些。但是這不會(huì)長久的(確信在5年或者15年后,這種競爭就不存在了)。是的,我在談?wù)揜ich Internet Applications, Ajax, 還有那些不可思議的交互應(yīng)用。他們讓W(xué)eb成為了一個(gè)真正的“無平臺(tái)”的平臺(tái),如果你知道我是怎么想的。

            16、信奉并支持快速改進(jìn)和反饋。這個(gè)通常意味著加快步伐,但也意味著使用輕量級(jí)的工具、技術(shù)和不要做出那些適得其反的痛苦決定(例如使用一個(gè)被層層環(huán)繞的Ajax框架來代替可以通過混合來實(shí)現(xiàn)的,或者用C++來構(gòu)建所有的東西,其實(shí)使用Ruby會(huì)更好一些)。這同時(shí)也意味著需要一個(gè)非常快速的方式來處理錯(cuò)誤報(bào)告,修復(fù)Bug,釋放新版本。從一個(gè)用戶的角度來看,報(bào)告你所發(fā)現(xiàn)的任何問題,還有那些你經(jīng)常抱怨的地方,甚至那些都不是一個(gè)Bug。

            當(dāng)然,Web 2.0是一個(gè)極其廣泛和深?yuàn)W的話題,沒有一個(gè)人能夠列舉出它的所有重點(diǎn)和特征。如果你對此充滿了興趣,請花一點(diǎn)時(shí)間來補(bǔ)充我沒有提到的地方。我想這就是Web 2.0的參與性吧! 
            posted @ 2007-10-08 11:43 colys 閱讀(367) | 評論 (0)編輯 收藏

            2007年8月24日 #

            http://www.cnblogs.com/hardrock/archive/2006/08/18/480668.html
            posted @ 2007-08-24 10:29 colys 閱讀(468) | 評論 (0)編輯 收藏

            2007年7月3日 #

            VS2005進(jìn)行Web調(diào)試的瀏覽器選擇
            不幸,安裝了firefox后,安裝VS2005,VS進(jìn)行web調(diào)試時(shí)就用了firefox而不是ie,這應(yīng)該是默認(rèn)瀏覽器搞的

            更改方法:

            打開 C:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\VisualStudio\8.0\browsers.xml

             
            <?xml version="1.0" ?> 
            <BrowserInfo>
            <Browser>
              
            <Name>firefox.exe</Name> 
              
            <Path>"F:\PROGRA~1\MOZILL~1\FIREFOX.EXE"</Path> 
              
            <Resolution>0</Resolution> 
              
            <IsDefault>False</IsDefault> 
              
            </Browser>
            <Browser>
              
            <Name>Microsoft Internet Explorer</Name> 
              
            <Path>"C:\Program Files\Internet Explorer\iexplore.exe"</Path> 
              
            <Resolution>0</Resolution> 
              
            <IsDefault>True</IsDefault> 
            <DDE>
              
            <Service>IExplore</Service> 
              
            <TopicOpenURL>WWW_OpenURL</TopicOpenURL> 
              
            <ItemOpenURL>"%s",,0xffffffff,3,,,,</ItemOpenURL> 
              
            <TopicActivate>WWW_Activate</TopicActivate> 
              
            <ItemActivate>0xffffffff,0</ItemActivate> 
              
            </DDE>
              
            </Browser>
            <InternalBrowser>
              
            <Resolution>0</Resolution> 
              
            <IsDefault>False</IsDefault> 
              
            </InternalBrowser>
              
            </BrowserInfo>
            將第一個(gè)<Browser>結(jié)點(diǎn),也就是firefox的<IsDefault>改為 False ,將 IExplore 的一個(gè)改為True
            或者直接刪除此文件
            posted @ 2007-07-03 22:25 colys 閱讀(1381) | 評論 (0)編輯 收藏

            2007年7月1日 #

            一、異步IO
                    對于應(yīng)用程序而言,有兩種類型的IO調(diào)用:即同步IO 與異步IO。其本質(zhì)的區(qū)別是:同步IO會(huì)block當(dāng)前的調(diào)用線程,而異步IO則允許發(fā)起IO請求的調(diào)用線程繼續(xù)執(zhí)行,等到IO請求被處理后,會(huì)通知調(diào)用 線程。在windows平臺(tái)上,應(yīng)用程序可以調(diào)用CreateFile API, 并通過設(shè)置FILE_FLAG_OVERLAPPED標(biāo)志來決定是否發(fā)起異步IO請求。
                    對于異步的IO請求,其最大的好處是:慢速的IO請求相對于應(yīng)用程序而言是異步執(zhí)行,這樣可以極大提高應(yīng)用程序的處理吞吐量。發(fā)起IO請求的應(yīng)用程序需要關(guān)心的是IO執(zhí)行完成的結(jié)果,而不必忙等IO請求執(zhí)行的過程。
                   事實(shí)上,無論對于同步IO,還是異步IO,當(dāng)IO請求發(fā)送到device driver后,device driver的執(zhí)行總是異步的,當(dāng)它接到IO請求之后,總會(huì)馬上返回給IO System。而IO System是否立即返回給調(diào)用線程,則取決于FILE_FLAG_OVERLAPPED標(biāo)志的設(shè)置,如下圖:


            二、異步IO的同步問題。
                    我們使用異步IO,是為了提高應(yīng)用程序的處理吞吐量。但是,當(dāng)異步IO不再異步時(shí)(無論你是否設(shè)置FILE_FLAG_OVERLAPPED標(biāo)志),應(yīng)用 程序的性能會(huì)受到極大的影響。根據(jù)Microsoft Knowledge Base 156932, 在下列幾種情況下,異步IO會(huì)失去它的異步性,而表現(xiàn)出同步的性質(zhì):
            1)如果文件使用了NTFS compression壓縮,則system driver不會(huì)異步地存取這樣的文件。
            2)擴(kuò)展文件長度的IO操作不會(huì)是異步操作。
            3)Cache機(jī)制。如果IO操作使用了file system cache,則這樣的IO操作會(huì)被當(dāng)成同步IO,而非異步IO。
            即使你使用了FILE_FLAG_OVERLAPPED標(biāo)志。在這種情況下,
            a.如果需要讀取的數(shù)據(jù)已經(jīng)在Cache里,那么I/O drivers會(huì)認(rèn)為這樣的IO請求可以被立即處理,其結(jié)果是ReadFile 或者WriteFile調(diào)用返回TRUE,表示是:同步處理完成。
            b. 如果需要讀取的數(shù)據(jù)不在Cache里,windows NT的file system是使用page-faulting機(jī)制來實(shí)現(xiàn)cache管理,而page-faulting總是被同步處理, Windows NT沒有提供異步的page-faulting機(jī)制。的確, file system driver使用了線程池來緩解這一問題,但是,當(dāng)應(yīng)用程序發(fā)起的IO請求足夠多時(shí),線程池還是不能應(yīng)付的。
                    在我們開發(fā)基于異步IO應(yīng)用程序時(shí),應(yīng)該避免上述問題的出現(xiàn),因?yàn)樗鼈儠?huì)使程序的性能大打折扣。
            那么,對于Cache,我們?nèi)绾伪苊饽兀看鸢甘牵赫埵褂肍ILE_FLAG_NO_BUFFERING標(biāo)志。這個(gè)標(biāo)志會(huì)使異步IO真實(shí)地異步執(zhí)行。
            三、性能的測試數(shù)據(jù)(僅供參考)。
                  我在我的機(jī)器上,簡單地對使用FILE_FLAG_NO_BUFFERING標(biāo)志的異步IO,與不使用FILE_FLAG_NO_BUFFERING標(biāo)志的異步IO進(jìn)行了對比。
            操作:順序讀取1G的文件。
            x軸表示:每次讀取的字節(jié)數(shù)(單位:K/每次)
            Y軸表示:讀取完成所需要的時(shí)間。(單位:millisecond)
            注意:每次測試讀取的內(nèi)容總數(shù)是相等的(1000M)。
            例如:如果每次讀取128k,則需要讀取8000次(128k*8000 = 1000M)。
            如果每次讀取256k,則需要讀取4000次(256k*4000 = 1000M)。
            粉紅色的線沒有使用FILE_FLAG_NO_BUFFERING標(biāo)志,而黃色的線使用了FILE_FLAG_NO_BUFFERING標(biāo)志。

            從以上的數(shù)據(jù),我們可以得出以下結(jié)論:
            1) 當(dāng)使用FILE_FLAG_NO_BUFFERING標(biāo)志,應(yīng)用程序的性能會(huì)極大提高,大概有50%的提高。
            2) 在使用異步IO的時(shí)候,還有一個(gè)注意的問題是:當(dāng)你每次讀取的字節(jié)數(shù)增大的時(shí)候,性能也會(huì)提高。尤其在小于1024k時(shí),當(dāng)增大次讀取的字節(jié)數(shù),性能都有 明顯的提高。在混合了網(wǎng)絡(luò)傳輸?shù)葟?fù)雜因素的應(yīng)用程序開發(fā)過程中,建議將該值設(shè)置為可配置的參數(shù),通過調(diào)整該參數(shù),使你的應(yīng)用達(dá)到最好的性能。

            參考資料:

            1) Microsoft Knowledge Base 156932

            2)  Microsoft Windows Internals, Fourth Edition.

            posted @ 2007-07-01 21:23 colys 閱讀(807) | 評論 (0)編輯 收藏

            2007年6月3日 #


            有5戶人家A,B,C,D,E,每戶人家都養(yǎng)了5只鴿子,一共25只。

            這5戶人家想從一共這25只鴿子中挑出飛的最快的前5只鴿子。

            大家選定了一個(gè)出發(fā)點(diǎn)和到達(dá)點(diǎn),每次只能放飛5只鴿子,在這樣情況下可以看到每次從出發(fā)地到目的地5只鴿子到達(dá)的先后順序,但是沒有計(jì)時(shí)器來計(jì)算時(shí)間。

            注:題目中不要考慮鴿子體能,是否勻速,是否直線飛行等等情況,可以理想設(shè)定速度均勻而且穩(wěn)速。
            ==============================================

            請問:
            A)在確保能挑出25只鴿子中飛的最快的5只的前提下,最少需要多少次比賽(每次只能5只)能保證能挑出最快的5只。

            B)怎樣比賽?
            posted @ 2007-06-03 16:34 colys 閱讀(1777) | 評論 (15)編輯 收藏

            2007年5月27日 #

              在運(yùn)行vs2003安裝時(shí)老提示我是要更新還是刪除,我都還沒裝怎么會(huì)有這個(gè)項(xiàng)呢!后來仔細(xì)看了看這個(gè)提示是屬于我裝的一個(gè)極點(diǎn)輸入法的! 卸載掉后安裝正常!

              事情可不是都那么順,安裝后運(yùn)行一切正常,欣喜.....花了我好多時(shí)間!
            但不過多久,在下一次開機(jī)后,它罷工了! 提示DI.DLL找不到! 多次運(yùn)行還是如此! 想都不想,重裝! 又是一陣等待...
            再運(yùn)行,oh,shit "找不到.dll 文件"

              無語..難道這就是microsoft的東東嗎? 為什么以前安裝和使用就沒遇到這問題嗎? 突然一個(gè)思想在我腦海里浮現(xiàn),既然安裝和輸入法會(huì)有關(guān),但運(yùn)行會(huì)不會(huì)也如此!但極點(diǎn)五筆不是被我卸載掉了嗎? 難道是五筆加加的問題?(我裝有兩個(gè)五筆輸入法~~) 于是乎卸載掉五筆加加!再裝吧...等待...

            終于.....正常了...感慨ing.....................

            posted @ 2007-05-27 23:50 colys 閱讀(543) | 評論 (0)編輯 收藏

            2007年5月18日 #

            本文討論:

            • 用于編寫單元測試的 NUnit
             
            • 用于創(chuàng)建代碼文檔資料的 NDoc
             
            • 用于生成解決方案的 NAnt
             
            • 用于生成代碼的 CodeSmith
             
            • 用于監(jiān)視代碼的 FxCop
             
            • 用于編譯少量代碼的 Snippet Compiler
             
            • 兩種不同的轉(zhuǎn)換器工具:ASP.NET 版本轉(zhuǎn)換器和 Visual Studio .NET 項(xiàng)目轉(zhuǎn)換器
             
            • 用于生成正則表達(dá)式的 Regulator
             
            • 用于分析程序集的 .NET Reflector
             

            本文使用了下列技術(shù):

            .NET、C# 或 Visual Basic .NET、Visual Studio .NET

            除非您使用能夠獲得的最佳工具,否則您無法期望生成一流的應(yīng)用程序。除了像 Visual Studio®.NET 這樣的著名工具以外,還可以從 .NET 社區(qū)獲得許多小型的、不太為人所知的工具。在本文中,我將向您介紹一些目前可以獲得的、面向 .NET 開發(fā)的最佳免費(fèi)工具。我將引導(dǎo)您完成一個(gè)有關(guān)如何使用其中每種工具的快速教程 — 一些工具在許多時(shí)候可以使您節(jié)約一分鐘,而另一些工具則可能徹底改變您編寫代碼的方式。因?yàn)槲乙诒酒恼轮薪榻B如此之多的不同工具,所以我無法詳盡討論其中每種工具,但您應(yīng)該了解到有關(guān)每種工具的足夠信息,以便判斷哪些工具對您的項(xiàng)目有用。


            本頁內(nèi)容
             Snippet Compiler 
             Regulator 
             CodeSmith 
             生成自定義模板 
             NUnit 
             編寫 NUnit 測試 
             FxCop 
             Lutz Roeder 的 .NET Reflector 
             NDoc 
             NAnt 
             實(shí)際運(yùn)行的 NAnt 
             轉(zhuǎn)換工具 
             小結(jié) 

            Snippet Compiler
            Snippet Compiler 是一個(gè)基于 Windows® 的小型應(yīng)用程序,您可以通過它來編寫、編譯和運(yùn)行代碼。如果您具有較小的代碼段,并且您不希望為其創(chuàng)建完整的 Visual Studio .NET 項(xiàng)目(以及伴隨該項(xiàng)目的所有文件),則該工具將很有用。

            例如,假設(shè)我希望向您說明如何從 Microsoft?.NET 框架中啟動(dòng)另一個(gè)應(yīng)用程序。在 Snippet Compiler 中,我將通過新建一個(gè)能夠創(chuàng)建小型控制臺(tái)應(yīng)用程序的文件開始。可以在該控制臺(tái)應(yīng)用程序的 Main 方法內(nèi)部創(chuàng)建代碼片段,而這正是我要在這里做的事情。下面的代碼片段演示了如何從 .NET 框架中創(chuàng)建記事本實(shí)例: 

            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName= "notepad.exe";
            proc.Start();
            proc.WaitForExit();

            當(dāng)然該代碼片段本身無法編譯,而這正是 Snippet Compiler 的用武之地。圖 1 顯示了 Snippet Compiler 中的這一代碼示例。


            按此在新窗口打開圖片
            圖 1 Snippet Compiler


            要測試該代碼片段,只須按 play(運(yùn)行)按鈕(綠色三角形),它就會(huì)在調(diào)試模式下運(yùn)行。該代碼片段將生成一個(gè)彈出式控制臺(tái)應(yīng)用程序,并且將顯示記事本。當(dāng)您關(guān)閉記事本時(shí),該控制臺(tái)應(yīng)用程序也將關(guān)閉。

            就我個(gè)人而言,我是在嘗試為某位向我求助的人士創(chuàng)建一個(gè)小型示例時(shí),才發(fā)現(xiàn) Snippet Compiler 是如此寶貴的 — 如果不使用該工具,則我通常必須新建一個(gè)項(xiàng)目,確保每個(gè)部分都能編譯通過,然后將代碼片段發(fā)送給求助者,并刪除該項(xiàng)目。Snippet Compiler 使得這一過程變得更加容易、更加愉快。

            Snippet Compiler 由 Jeff Key 編寫,并且可以從 http://www.sliver.com/dotnet/SnippetCompiler 下載。

            返回頁首
            Regulator
            Regulator 是最后一個(gè)添加到我的頭等工具清單中的。它是一種很有特色的工具,能夠使生成和測試正則表達(dá)式變得很容易。人們對正則表達(dá)式重新產(chǎn)生了興趣,因?yàn)樗鼈冊?nbsp;.NET 框架中受到很好的支持。正則表達(dá)式用來基于字符、頻率和字符順序定義字符串中的模式。它們最常見的用途是作為驗(yàn)證用戶輸入有效性的手段或者作為在較大字符串中查找字符串的方法 — 例如,在 Web 頁上查找 URL 或電子郵件地址。

            Regulator 使您可以輸入一個(gè)正則表達(dá)式以及一些針對其運(yùn)行該表達(dá)式的輸入內(nèi)容。這樣,在應(yīng)用程序中實(shí)現(xiàn)該正則表達(dá)式之前,您可以了解它將產(chǎn)生什么效果以及它將返回哪些種類的匹配項(xiàng)。圖 2 顯示了帶有簡單正則表達(dá)式的 Regulator。

            文檔中包含該正則表達(dá)式 — 在該示例中,它是 [0-9]*,應(yīng)該匹配一行中任意數(shù)量的數(shù)字。右下側(cè)的框中含有針對該正則表達(dá)式的輸入,而左下側(cè)的框顯示了該正則表達(dá)式在輸入內(nèi)容中找到的匹配項(xiàng)。在這樣的單獨(dú)應(yīng)用程序中編寫和測試正則表達(dá)式,要比嘗試在您的應(yīng)用程序中處理它們?nèi)菀椎枚唷?br>
            Regulator 中的最佳功能之一是能夠在 regexlib.com 搜索聯(lián)機(jī)正則表達(dá)式庫。例如,如果您在搜索框中輸入字符串“phone”,您將找到 20 種以上能夠匹配各種電話號(hào)碼的不同的正則表達(dá)式,包括用于英國、澳大利亞的表達(dá)式以及其他許多電話號(hào)碼。Regulator 由 Roy Osherove 編寫,并且可以在 http://royo.is-a-geek.com/regulator 下載。

            返回頁首
            CodeSmith
            CodeSmith 是一種基于模板的代碼生成工具,它使用類似于 ASP.NET 的語法來生成任意類型的代碼或文本。與其他許多代碼生成工具不同,CodeSmith 不要求您訂閱特定的應(yīng)用程序設(shè)計(jì)或體系結(jié)構(gòu)。使用 CodeSmith,可以生成包括簡單的強(qiáng)類型集合和完整應(yīng)用程序在內(nèi)的任何東西。

            當(dāng)您生成應(yīng)用程序時(shí),您經(jīng)常需要重復(fù)完成某些特定的任務(wù),例如編寫數(shù)據(jù)訪問代碼或者生成自定義集合。CodeSmith 在這些時(shí)候特別有用,因?yàn)槟梢跃帉懩0遄詣?dòng)完成這些任務(wù),從而不僅提高您的工作效率,而且能夠自動(dòng)完成那些最為乏味的任務(wù)。CodeSmith 附帶了許多模板,包括對應(yīng)于所有 .NET 集合類型的模板以及用于生成存儲(chǔ)過程的模板,但該工具的真正威力在于能夠創(chuàng)建自定義模板。為了使您能夠入門,我將快速介紹一下如何生成自定義模板。

            返回頁首
            生成自定義模板
            CodeSmith 模板只是一些可以在任意文本編輯器中創(chuàng)建的文本文件。它們的唯一要求是用 .cst 文件擴(kuò)展名來保存它們。我將要生成的示例模板將接受一個(gè)字符串,然后基于該字符串生成一個(gè)類。創(chuàng)建模板的第一步是添加模板頭,它可聲明模板的語言、目標(biāo)語言以及簡要模板說明: 

            <%@ CodeTemplate Language="C#"    
               TargetLanguage="C#" 
               Description="Car Template" %>

            模板的下一部分是屬性聲明,在這里可聲明將在模板每次運(yùn)行時(shí)指定的屬性。就該模板而言,我要使用的唯一屬性只是一個(gè)字符串,因此屬性聲明如下所示: 

            <%@ Property Name="ClassName" Type="String" Category="Context" 
                Description="Class Name" %>

            該屬性聲明將使 ClassName 屬性出現(xiàn)在 CodeSmith 屬性窗口中,以便可以在模板運(yùn)行時(shí)指定它。下一步是實(shí)際生成模板主體,它非常類似于用 ASP.NET 進(jìn)行編碼。您可以在圖 3 中查看該模板的主體。[編輯更新 — 6/16/2004:圖 3 中的代碼已被更新,以便對多線程操作保持安全。]

            正如您所見,該模板接受字符串輸入并使用該類名生成單獨(dú)的類。在模板主體中,使用與 ASP.NET 中相同的起始和結(jié)束標(biāo)記。在該模板中,我只是插入屬性值,但您還可以在這些標(biāo)記內(nèi)部使用任意類型的 .NET 代碼。在該模板完成之后,您就可以通過雙擊它或者從 CodeSmith 應(yīng)用程序中打開它將其加載到 CodeSmith 中。圖 4 顯示了已經(jīng)加載到 CodeSmith 中的該模板。

            您可以看到左側(cè)的屬性正是我在該模板中聲明的屬性。如果我輸入“SingletonClass”作為類名,并單擊 Generate 按鈕,則將生成圖 3 的底部顯示的類。

            CodeSmith 使用起來相當(dāng)容易,如果能夠正確應(yīng)用,則可以產(chǎn)生一些令人難以置信的結(jié)果。面向代碼生成的應(yīng)用程序中最常見的部分之一是數(shù)據(jù)訪問層。CodeSmith 包括一個(gè)名為 SchemaExplorer 的特殊的程序集,可用來從表、存儲(chǔ)過程或幾乎任何其他 SQL Server? 對象生成模板。

            CodeSmith 由 Eric J. Smith 編寫,并且可以在 http://www.ericjsmith.net/codesmith 下載。

            返回頁首
            NUnit
            NUnit 是為 .NET 框架生成的開放源代碼單元測試框架。NUnit 使您可以用您喜歡的語言編寫測試,從而測試應(yīng)用程序的特定功能。當(dāng)您首次編寫代碼時(shí),單元測試是一種測試代碼功能的很好方法,它還提供了一種對應(yīng)用程序進(jìn)行回歸測試的方法。NUnit 應(yīng)用程序提供了一個(gè)用于編寫單元測試的框架,以及一個(gè)運(yùn)行這些測試和查看結(jié)果的圖形界面。

            返回頁首
            編寫 NUnit 測試
            作為示例,我將測試 .NET 框架中 Hashtable 類的功能,以確定是否可以添加兩個(gè)對象并且隨后檢索這些對象。我的第一步是添加對 NUnit.Framework 程序集的引用,該程序集將賦予我對 NUnit 框架的屬性和方法的訪問權(quán)。接下來,我將創(chuàng)建一個(gè)類并用 TestFixture 屬性標(biāo)記它。該屬性使 NUnit 可以知道該類包含 NUnit 測試: 

            using System;
            using System.Collections;
            using NUnit.Framework;

            namespace NUnitExample
            {
                [TestFixture]
                public class HashtableTest {
                    public HashtableTest() {
                        
                    }
                }
            }

            下一步,我將創(chuàng)建一個(gè)方法并用 [Test] 屬性標(biāo)記它,以便 NUnit 知道該方法是一個(gè)測試。然后,我將建立一個(gè) Hashtable 并向其添加兩個(gè)值,再使用 Assert.AreEqual 方法查看我是否可以檢索到與我添加到 Hashtable 的值相同的值,如下面的代碼所示: 

            [Test]
            public void HashtableAddTest()
            {
                Hashtable ht = new Hashtable();
                        
                ht.Add("Key1", "Value1");
                ht.Add("Key2", "Value2");

                Assert.AreEqual("Value1", ht["Key1"], "Wrong object returned!");
                Assert.AreEqual("Value2", ht["Key2"], "Wrong object returned!");
            }

            這將確認(rèn)我可以首先向 Hashtable 中添加值并隨后檢索相應(yīng)的值 — 這是一個(gè)很簡單的測試,但能夠表現(xiàn) NUnit 的功能。存在許多測試類型以及各種 Assert 方法,可使用它們來測試代碼的每個(gè)部分。

            要運(yùn)行該測試,我需要生成項(xiàng)目,在 NUnit 應(yīng)用程序中打開生成的程序集,然后單擊 Run 按鈕。圖 5 顯示了結(jié)果。當(dāng)我看到那個(gè)大的綠色條紋時(shí),我有一種興奮和頭暈的感覺,因?yàn)樗屛抑罍y試已經(jīng)通過了。這個(gè)簡單的示例表明 NUnit 和單元測試是多么方便和強(qiáng)大。由于能夠編寫可以保存的單元測試,并且每當(dāng)您更改代碼時(shí)都可以重新運(yùn)行該單元測試,您不僅可以更容易地檢測到代碼中的缺陷,而且最終能夠交付更好的應(yīng)用程序。


            按此在新窗口打開圖片
            圖 5 NUnit


            NUnit 是一個(gè)開放源代碼項(xiàng)目,并且可以從 http://www.nunit.org 下載。還有一個(gè)優(yōu)秀的 NUnit Visual Studio .NET 外接程序,它使您可以直接從 Visual Studio 中運(yùn)行單元測試。您可以在 http://sourceforge.net/projects/nunitaddin 找到它。有關(guān) NUnit 及其在測試驅(qū)動(dòng)開發(fā)中的地位的詳細(xì)信息,請參閱文章“Test-Driven C#: Improve the Design and Flexibility of Your Project with Extreme Programming Techniques”(MSDN ®Magazine 2004 年 4 月刊)。

            返回頁首
            FxCop
            .NET 框架非常強(qiáng)大,這意味著存在創(chuàng)建優(yōu)秀應(yīng)用程序的極大可能,但是也同樣存在創(chuàng)建劣質(zhì)程序的可能。FxCop 是有助于創(chuàng)建更好的應(yīng)用程序的工具之一,它所采用的方法是:使您能夠分析程序集,并使用一些不同的規(guī)則來檢查它是否符合這些規(guī)則。FxCop 隨附了由 Microsoft 創(chuàng)建的固定數(shù)量的規(guī)則,但您也可以創(chuàng)建并包括您自己的規(guī)則。例如,如果您決定所有的類都應(yīng)該具有一個(gè)不帶任何參數(shù)的默認(rèn)構(gòu)造函數(shù),則可以編寫一條規(guī)則,以確保程序集的每個(gè)類上都具有一個(gè)構(gòu)造函數(shù)。這樣,無論是誰編寫該代碼,您都將獲得一定程度的一致性。如果您需要有關(guān)創(chuàng)建自定義規(guī)則的詳細(xì)信息,請參閱 John Robbins 的有關(guān)該主題的 Bugslayer 專欄文章(MSDN ® Magazine 2004 年 6 月刊)。

            那么,讓我們觀察一下實(shí)際運(yùn)行的 FxCop,并且看一下它在我一直在處理的 NUnitExample 程序集中找到哪些錯(cuò)誤。當(dāng)您打開 FxCop 時(shí),您首先需要?jiǎng)?chuàng)建一個(gè) FxCop 項(xiàng)目,然后向其添加您要測試的程序集。在將該程序集添加到項(xiàng)目以后,就可以按 Analyze,F(xiàn)xCop 將分析該程序集。圖 6 中顯示了在該程序集中找到的錯(cuò)誤和警告。

            FxCop 在我的程序集中找到了幾個(gè)問題。您可以雙擊某個(gè)錯(cuò)誤以查看詳細(xì)信息,包括規(guī)則說明以及在哪里可以找到更多信息。(您可以做的一件有趣的事情是在框架程序集上運(yùn)行 FxCop 并查看發(fā)生了什么事情。)

            FxCop 可以幫助您創(chuàng)建更好的、更一致的代碼,但它無法補(bǔ)償?shù)土拥膽?yīng)用程序設(shè)計(jì)或非常簡單拙劣的編程。FxCop 也不能替代對等代碼檢查,但是因?yàn)樗梢栽谶M(jìn)行代碼檢查之前捕獲大量錯(cuò)誤,所以您可以花費(fèi)更多時(shí)間來解決嚴(yán)重的問題,而不必?fù)?dān)心命名約定。FxCop 由 Microsoft 開發(fā),并且可以從 http://www.gotdotnet.com/team/fxcop 下載。

            返回頁首
            Lutz Roeder 的 .NET Reflector
            下一個(gè)必不可少的工具稱為 .NET Reflector,它是一個(gè)類瀏覽器和反編譯器,可以分析程序集并向您展示它的所有秘密。.NET 框架向全世界引入了可用來分析任何基于 .NET 的代碼(無論它是單個(gè)類還是完整的程序集)的反射概念。反射還可以用來檢索有關(guān)特定程序集中包含的各種類、方法和屬性的信息。使用 .NET Reflector,您可以瀏覽程序集的類和方法,可以分析由這些類和方法生成的 Microsoft 中間語言 (MSIL),并且可以反編譯這些類和方法并查看 C# 或 Visual Basic ®.NET 中的等價(jià)類和方法。

            為了演示 .NET Reflector 的工作方式,我將加載和分析前面已經(jīng)顯示的 NUnitExample 程序集。圖 7 顯示了 .NET Reflector 中加載的該程序集。


            按此在新窗口打開圖片
            圖 7 NUnitExample 程序集


            在 .NET Reflector 內(nèi)部,有各種可用來進(jìn)一步分析該程序集的工具。要查看構(gòu)成某個(gè)方法的 MSIL,請單擊該方法并從菜單中選擇 Disassembler。

            除了能夠查看 MSIL 以外,您還可以通過選擇 Tools 菜單下的 Decompiler 來查看該方法的 C# 形式。通過在 Languages 菜單下更改您的選擇,您還可以查看該方法被反編譯到 Visual Basic .NET 或 Delphi 以后的形式。以下為 .NET Reflector 生成的代碼: 

            public void HashtableAddTest()

                Hashtable hashtable1;
                hashtable1 = new Hashtable();
                hashtable1.Add("Key1", "Value1");
                hashtable1.Add("Key2", "Value2");
                Assert.AreEqual("Value1", hashtable1["Key1"], 
                   "Wrong object returned!");
                Assert.AreEqual("Value2", hashtable1["Key2"],
                   "Wrong object returned!");
            }

            前面的代碼看起來非常像我為該方法實(shí)際編寫的代碼。以下為該程序集中的實(shí)際代碼: 

            public void HashtableAddTest()
            {
                Hashtable ht = new Hashtable();
                        
                ht.Add("Key1", "Value1");
                ht.Add("Key2", "Value2");

                Assert.AreEqual("Value1", ht["Key1"],
                    "Wrong object returned!");
                Assert.AreEqual("Value2", ht["Key2"],
                    "Wrong object returned!");
            }

            盡管上述代碼中存在一些小的差異,但它們在功能上是完全相同的。

            雖然該示例是一種顯示實(shí)際代碼與反編譯代碼之間對比的好方法,但在我看來,它并不代表 .NET Reflector 所具有的最佳用途 — 分析 .NET 框架程序集和方法。.NET 框架提供了許多執(zhí)行類似操作的不同方法。例如,如果您需要從 XML 中讀取一組數(shù)據(jù),則存在多種使用 XmlDocument、XPathNavigator 或 XmlReader 完成該工作的不同方法。通過使用 .NET Reflector,您可以查看 Microsoft 在編寫數(shù)據(jù)集的 ReadXml 方法時(shí)使用了什么,或者查看他們在從配置文件讀取數(shù)據(jù)時(shí)做了哪些工作。.NET Reflector 還是一個(gè)了解以下最佳實(shí)施策略的優(yōu)秀方法:創(chuàng)建諸如 HttpHandlers 或配置處理程序之類的對象,因?yàn)槟梢粤私獾?nbsp;Microsoft 工作組實(shí)際上是如何在框架中生成這些對象的。

            .NET Reflector 由 Lutz Roeder 編寫,并且可以從 http://www.aisto.com/roeder/dotnet 下載。

            返回頁首
            NDoc
            編寫代碼文檔資料幾乎總是一項(xiàng)令人畏懼的任務(wù)。我所說的不是早期設(shè)計(jì)文檔,甚至也不是更為詳細(xì)的設(shè)計(jì)文檔;我說的是記錄類上的各個(gè)方法和屬性。NDoc 工具能夠使用反射來分析程序集,并使用從 C# XML 注釋生成的 XML 自動(dòng)為代碼生成文檔資料。XML 注釋僅適用于 C#,但有一個(gè)名為 VBCommenter 的 Visual Studio .NET Power Toy,它能夠?yàn)?nbsp;Visual Basic .NET 完成類似的工作。此外,下一版本的 Visual Studio 將為更多語言支持 XML 注釋。

            使用 NDoc 時(shí),您仍然在編寫代碼的技術(shù)文檔,但您是在編寫代碼的過程中完成了文檔編寫工作(在 XML 注釋中),而這更容易忍受。使用 NDoc 時(shí),第一步是為您的程序集打開 XML 注釋生成功能。右鍵單擊該項(xiàng)目并選擇 Properties | Configuration Properties | Build,然后在 XML Documentation File 選項(xiàng)中輸入用于保存 XML 文件的路徑。當(dāng)該項(xiàng)目生成時(shí),將創(chuàng)建一個(gè) XML 文件,其中包含所有 XML 注釋。下面是 NUnit 示例中的一個(gè)用 XML 編寫了文檔的方法: 

            /// <summary>
            /// This test adds a number of values to the Hashtable collection 
            /// and then retrieves those values and checks if they match.
            /// </summary>
            [Test]
            public void HashtableAddTest()
            {
                //Method Body Here
            }

            有關(guān)該方法的 XML 文檔資料將被提取并保存在 XML 文件中,如下所示: 

            <member name="M:NUnitExample.HashtableTest.HashtableAddTest">
              <summary>This test adds a number of values to the Hashtable collection
                and then retrieves those values and checks if they match.</summary> 
            </member>

            NDoc 使用反射來考察您的程序集,然后讀取該文檔中的 XML,并且將它們進(jìn)行匹配。NDoc 使用該數(shù)據(jù)來創(chuàng)建任意數(shù)量的不同文檔格式,包括 HTML 幫助文件 (CHM)。在生成 XML 文件以后,下一步是將程序集和 XML 文件加載到 NDoc 中,以便可以對它們進(jìn)行處理。通過打開 NDoc 并單擊 Add 按鈕,可以容易地完成該工作。

            在將程序集和 XML 文件加載到 NDoc 中并且使用可用的屬性范圍自定義輸出以后,單擊 Generate 按鈕將啟動(dòng)生成文檔資料的過程。使用默認(rèn)的屬性,NDoc 可以生成一些非常吸引人并且實(shí)用的 .html 和 .chm 文件,從而以快速有效的方式自動(dòng)完成原來非常乏味的任務(wù)。

            NDoc 是一個(gè)開放源代碼項(xiàng)目,并且可以從 http://ndoc.sourceforge.net 下載。

            返回頁首
            NAnt
            NAnt 是一個(gè)基于 .NET 的生成工具,與當(dāng)前版本的 Visual Studio .NET 不同,它使得為您的項(xiàng)目創(chuàng)建生成過程變得非常容易。當(dāng)您擁有大量從事單個(gè)項(xiàng)目的開發(fā)人員時(shí),您不能依賴于從單個(gè)用戶的座位進(jìn)行生成。您也不希望必須定期手動(dòng)生成該項(xiàng)目。您更愿意創(chuàng)建每天晚上運(yùn)行的自動(dòng)生成過程。NAnt 使您可以生成解決方案、復(fù)制文件、運(yùn)行 NUnit 測試、發(fā)送電子郵件,等等。遺憾的是,NAnt 缺少漂亮的圖形界面,但它的確具有可以指定應(yīng)該在生成過程中完成哪些任務(wù)的控制臺(tái)應(yīng)用程序和 XML 文件。注意,MSBuild(屬于 Visual Studio 2005 的新的生成平臺(tái))為每種健壯的生成方案進(jìn)行了準(zhǔn)備,并且由基于 XML 的項(xiàng)目文件以類似的方式驅(qū)動(dòng)。

            返回頁首
            實(shí)際運(yùn)行的 NAnt
            在該示例中,我將為前面創(chuàng)建的 NUnitExample 解決方案創(chuàng)建一個(gè) NAnt 版本文件。首先,我需要?jiǎng)?chuàng)建一個(gè)具有 .build 擴(kuò)展名的 XML 文件,將其放在我的項(xiàng)目的根目錄中,然后向該文件的頂部添加一個(gè) XML 聲明。我需要添加到該文件的第一個(gè)標(biāo)記是 project 標(biāo)記: 

            <?xml version="1.0"?>
            <project name="NUnit Example" default="build" basedir=".">
                <description>The NUnit Example Project</description>
            </project>

            項(xiàng)目標(biāo)記還用于設(shè)置項(xiàng)目名稱、默認(rèn)目標(biāo)以及基目錄。Description 標(biāo)記用于設(shè)置該項(xiàng)目的簡短說明。

            接下來,我將添加 property 標(biāo)記,該標(biāo)記可用于將設(shè)置存儲(chǔ)到單個(gè)位置(隨后可以從文件中的任意位置訪問該位置)。在該例中,我將創(chuàng)建一個(gè)名為 debug 的屬性,我可以隨后將其設(shè)置為 true 或 false,以反映我是否要在調(diào)試配置下編譯該項(xiàng)目。(最后,這一特定屬性并未真正影響如何生成該項(xiàng)目;它只是您設(shè)置的一個(gè)變量,當(dāng)您真正確定了如何生成該項(xiàng)目時(shí)將讀取該變量。)

            接下來,我需要?jiǎng)?chuàng)建一個(gè) target 標(biāo)記。一個(gè)項(xiàng)目可以包含多個(gè)可在 NAnt 運(yùn)行時(shí)指定的 target。如果未指定 target,則使用默認(rèn) target(我在 project 元素中設(shè)置的 target)。在該示例中,默認(rèn) target 是 build。讓我們觀察一下 target 元素,它將包含大多數(shù)生成信息: 

            <target name="build" description="compiles the source code">
            </target>

            在 target 元素內(nèi),我將把 target 的名稱設(shè)置為 build,并且創(chuàng)建有關(guān)該 target 將做哪些工作的說明。我還將創(chuàng)建一個(gè) csc 元素,該元素用于指定應(yīng)該傳遞給 csc C# 編譯器的數(shù)據(jù)。讓我們看一下該 csc 元素: 

            <csc target="library" output=".\bin\debug\NUnitExample.dll" 
                debug="${debug}">
            <references>
                <includes name="C:\program files\NUnit V2.1\bin\NUnit.Framework.dll"/>
            </references>
                <sources>
                   <includes name="HashtableTest.cs"/>
                </sources>
            </csc>

            首先,我必須設(shè)置該 csc 元素的 target。在該例中,我將創(chuàng)建一個(gè) .dll 文件,因此我將 target 設(shè)置為 library。接下來,我必須設(shè)置 csc 元素的 output,它是將要?jiǎng)?chuàng)建 .dll 文件的位置。最后,我需要設(shè)置 debug 屬性,它確定了是否在調(diào)試中編譯該項(xiàng)目。因?yàn)槲以谇懊鎰?chuàng)建了一個(gè)用于存儲(chǔ)該值的屬性,所以我可以使用下面的字符串來訪問該屬性的值:${debug}。Csc 元素還包含一些子元素。我需要?jiǎng)?chuàng)建兩個(gè)元素:references 元素將告訴 NAnt 需要為該項(xiàng)目引用哪些程序集,sources 元素告訴 NAnt 要在生成過程中包含哪些文件。在該示例中,我引用了 NUnit.Framework.dll 程序集并包含了 HashtableTest.cs 文件。圖 8 中顯示了完整的生成文件。(您通常還要?jiǎng)?chuàng)建一個(gè)干凈的 target,用于刪除生成的文件,但為了簡潔起見,我已經(jīng)將其省略。)

            要生成該文件,我需要轉(zhuǎn)到我的項(xiàng)目的根目錄(生成文件位于此處),然后從該位置執(zhí)行 nant.exe。如果生成成功,您可以在該應(yīng)用程序的 bin 目錄中找到 .dll 和 .pdb 文件。盡管使用 NAnt 肯定不像在 Visual Studio 中單擊 Build 那樣簡單,但它仍然是一種非常強(qiáng)大的工具,可用于開發(fā)按自動(dòng)計(jì)劃運(yùn)行的生成過程。NAnt 還包括一些有用的功能,例如能夠運(yùn)行單元測試或者復(fù)制附加文件(這些功能沒有受到當(dāng)前 Visual Studio 生成過程的支持)。

            NAnt 是一個(gè)開放源代碼項(xiàng)目,并且可以從 http://nant.sourceforge.net 下載。

            返回頁首
            轉(zhuǎn)換工具
            我已經(jīng)將兩個(gè)獨(dú)立的工具合在一起放在標(biāo)題“轉(zhuǎn)換工具”下面。這兩個(gè)工具都非常簡單,但又可能極為有用。第一個(gè)工具是 ASP.NET 版本轉(zhuǎn)換器,它可用于轉(zhuǎn)換 ASP.NET(虛擬目錄在它下面運(yùn)行)的版本。第二個(gè)工具是 Visual Studio Converter,它可用于將項(xiàng)目文件從 Visual Studio .NET 2002 轉(zhuǎn)換到 Visual Studio .NET 2003。

            當(dāng) IIS 處理請求時(shí),它會(huì)查看正在請求的文件的擴(kuò)展名,然后基于該 Web 站點(diǎn)或虛擬目錄的擴(kuò)展名映射,將請求委派給 ISAPI 擴(kuò)展或者自己處理該請求。這正是 ASP.NET 的工作方式;將為所有 ASP.NET 擴(kuò)展名注冊擴(kuò)展名映射,并將這些擴(kuò)展名映射導(dǎo)向 aspnet_isapi.dll。這種工作方式是完美無缺的,除非您安裝了 ASP.NET 1.1 — 它會(huì)將擴(kuò)展名映射升級(jí)到新版本的 aspnet_isapi.dll。當(dāng)在 ASP.NET 1.0 上生成的應(yīng)用程序試圖用 1.1 版運(yùn)行時(shí),這會(huì)導(dǎo)致錯(cuò)誤。要解決該問題,可以將所有擴(kuò)展名映射重新轉(zhuǎn)換到 1.0 版的 aspnet_isapi.dll,但是由于有 18 種擴(kuò)展名映射,所以手動(dòng)完成這一工作將很枯燥。這正是 ASP.NET 版本轉(zhuǎn)換器可以發(fā)揮作用的時(shí)候。使用這一小型實(shí)用工具,可以轉(zhuǎn)換任何單個(gè) ASP.NET 應(yīng)用程序所使用的 .NET 框架的版本。


            按此在新窗口打開圖片
            圖 9 ASP.NET 版本轉(zhuǎn)換器


            圖 9 顯示了實(shí)際運(yùn)行的 ASP.NET 版本轉(zhuǎn)換器。它的使用方法非常簡單,只須選擇相應(yīng)的應(yīng)用程序,然后選擇您希望該應(yīng)用程序使用的 .NET 框架版本。該工具隨后將使用 aspnet_regiis.exe 命令行工具將該應(yīng)用程序轉(zhuǎn)換到所選版本的框架。隨著將來版本的 ASP.NET 和 .NET 框架的發(fā)布,該工具將變得更為有用。

            ASP.NET 版本轉(zhuǎn)換器由 Denis Bauer 編寫,并且可以從 http://www.denisbauer.com/NETTools/ASPNETVersionSwitcher.aspx 下載。

            Visual Studio .NET 項(xiàng)目轉(zhuǎn)換器(參見圖 10)非常類似于 ASP.NET 版本轉(zhuǎn)換器,區(qū)別在于它用于轉(zhuǎn)換 Visual Studio 項(xiàng)目文件的版本。盡管在 .NET 框架的 1.0 版和 1.1 版之間只有很小的差異,但一旦將項(xiàng)目文件從 Visual Studio .NET 2002 轉(zhuǎn)換到 Visual Studio .NET 2003,將無法再把它轉(zhuǎn)換回去。雖然這在大多數(shù)時(shí)候可能不會(huì)成為問題(因?yàn)樵?nbsp;.NET 框架 1.0 版和 1.1 版之間幾乎沒有什么破壞性的更改),但在某些時(shí)刻您可能需要將項(xiàng)目轉(zhuǎn)換回去。該轉(zhuǎn)換器可以將任何解決方案或項(xiàng)目文件從 Visual Studio 7.1 (Visual Studio .NET 2003) 轉(zhuǎn)換到 Visual Studio 7.0 (Visual Studio .NET 2002),并在必要時(shí)進(jìn)行反向轉(zhuǎn)換。


            按此在新窗口打開圖片
            圖 10 Visual Studio .NET 項(xiàng)目轉(zhuǎn)換器


            Visual Studio .NET 項(xiàng)目轉(zhuǎn)換器由 Dacris Software 編寫。該工具可以從 http://www.codeproject.com/macro/vsconvert.asp 下載。

            返回頁首
            小結(jié)
            本文采用走馬觀花的方式介紹了上述工具,但我已經(jīng)試圖起碼向您提供足夠的信息以激起您的好奇心。我相信本文已經(jīng)讓您在某種程度上領(lǐng)悟了幾個(gè)免費(fèi)工具,您可以立即開始使用這些工具來編寫更好的項(xiàng)目。同時(shí),我還要敦促您確保自己擁有所有其他可以獲得的合適工具,無論是最新版本的 Visual Studio、功能強(qiáng)大的計(jì)算機(jī)還是免費(fèi)的實(shí)用工具。擁有合適的工具將使一切變得大不相同。

            James Avery 是一位使用 .NET 和其他 Microsoft 技術(shù)的顧問。他已經(jīng)撰寫了許多書籍和文章,他的最新著作是《ASP.NET Setup and Configuration Pocket Reference》(Microsoft Press, 2003)。您可以通過 javery@infozerk.com 向他發(fā)送電子郵件,并且在 http://www.dotavery.com/blog 閱讀他的網(wǎng)絡(luò)日記。
            posted @ 2007-05-18 23:11 colys 閱讀(652) | 評論 (5)編輯 收藏

            2007年5月15日 #

            面向?qū)ο蟮脑O(shè)計(jì)模式是經(jīng)驗(yàn)的總結(jié),MVC思想是原先用于構(gòu)建用戶界面的。這篇文章主要論述了如何在新的Web應(yīng)用領(lǐng)域中使用設(shè)計(jì)模式和MVC架構(gòu)。文章首先介紹了設(shè)計(jì)模式的概念和特點(diǎn),以及MVC架構(gòu)的設(shè)計(jì)思想,并分析了MVC架構(gòu)中包含的幾種主要的模式。然后根據(jù)Web應(yīng)用系統(tǒng)的特點(diǎn),就如何應(yīng)用模式和MVC架構(gòu)提出了一些設(shè)計(jì)思路。

            1. 引言
            1.1 設(shè)計(jì)模式

            面向?qū)ο蠹夹g(shù)的出現(xiàn)和應(yīng)用大大提高了軟件的重用性和軟件的質(zhì)量。面向?qū)ο蟮木幊桃脖纫酝母鞣N編程模式要簡單和高效,但是面向?qū)ο蟮脑O(shè)計(jì)方法要比以往的設(shè)計(jì)方法要復(fù)雜和有技巧得多,一個(gè)良好的設(shè)計(jì)應(yīng)該既具有對問題的針對性,也充分考慮到對將來問題和需求有足夠的通用性。在過去的十幾年中,人們在對面向?qū)ο蠹夹g(shù)的研究探索和實(shí)際應(yīng)用中針對某些問題創(chuàng)造了一些良好的解決方案,即所謂的面向?qū)ο蟮脑O(shè)計(jì)模式。面向?qū)ο蠹夹g(shù)的目的之一就是提高軟件的重用性,而對設(shè)計(jì)模式、設(shè)計(jì)方案的重用則從更深的層次上體現(xiàn)了重用的意義和本質(zhì)。
            人們對設(shè)計(jì)模式有很多定義,其中被引用的最多是Christopher Alexander的設(shè)計(jì)模式的定義:每一個(gè)設(shè)計(jì)模式是一個(gè)三方的規(guī)則,它表達(dá)了一個(gè)上下文環(huán)境(Context),一個(gè)問題和一個(gè)解決方案。設(shè)計(jì)模式一般有如下幾個(gè)基本要素:模式名稱,問題,目的,解決方案,效果,樣例代碼和相關(guān)設(shè)計(jì)模式。
            設(shè)計(jì)模式的分類有好幾種,可以根據(jù)其目的分為創(chuàng)建型(Creational),結(jié)構(gòu)型(Structural)和行為型(Behavioral)三種。創(chuàng)建型模式主要是用來創(chuàng)建對象,結(jié)構(gòu)型模式主要是處理類或?qū)ο蟮慕M合,行為型模式則主要用來描述對類或?qū)ο笤鯓咏换ズ驮鯓臃峙渎氊?zé)。也可以根據(jù)范圍將設(shè)計(jì)模式分為類模式和對象模式,類模式處理類和子類之間的關(guān)系,這些關(guān)系通過繼承建立,在編譯時(shí)刻就被確定下來,是屬于靜態(tài)的。對象模式是處理對象間的關(guān)系,這些關(guān)系在運(yùn)行時(shí)刻變化,更具動(dòng)態(tài)性。
            模式的特點(diǎn):是通過經(jīng)驗(yàn)獲取的,以某種結(jié)構(gòu)化的格式書寫下來,避免了遇到相同的問題重頭設(shè)計(jì),存在于不同的抽象層,在不斷完善的,是可重用的人工產(chǎn)物,使設(shè)計(jì)和最好的練習(xí)交互,以被組合起來解決更大的問題。

            1.2 MVC架構(gòu)
            MVC最初是在Smalltalk-80中被用來構(gòu)建用戶界面的。M代表模型Model, V代表視圖 View, C代表 控制器Controller。
            MVC的目的是增加代碼的重用率,減少數(shù)據(jù)表達(dá),數(shù)據(jù)描述和應(yīng)用操作的耦合度。 同時(shí)也使得軟件可維護(hù)性,可修復(fù)性,可擴(kuò)展性,靈活性以及封裝性大大提高。
            單用戶的應(yīng)用通常是以事件驅(qū)動(dòng)的用戶界面為組織結(jié)構(gòu)的。開發(fā)人員用一個(gè)界面工具畫了一個(gè)用戶接口界面,然后編寫代碼根據(jù)用戶輸入去執(zhí)行相應(yīng)的動(dòng)作,許多交互式的開發(fā)環(huán)境鼓勵(lì)這么做,因?yàn)樗鼜?qiáng)調(diào)先有界面然后再有功能。一些軟件設(shè)計(jì)模式策略是這樣的,然后經(jīng)常將固定后的代碼融入最后的系統(tǒng)當(dāng)中。導(dǎo)致的結(jié)果就是,程序組織圍繞用戶界面元素和用戶在那些界面元素上的動(dòng)作,數(shù)據(jù)的存儲(chǔ),應(yīng)用的功能以及用來顯示的代碼都雜亂無章的纏繞在一起。在單用戶的系統(tǒng)里代碼結(jié)構(gòu)是可以這樣的,因?yàn)橄到y(tǒng)需求不會(huì)頻繁變化。但是對一個(gè)大的系統(tǒng)如大型Web系統(tǒng),或電子商務(wù)系統(tǒng)來說就不太適用了。
            通過把數(shù)據(jù)模式從各種可以被存取和控制的數(shù)據(jù)中分離出來可以改善分布式系統(tǒng)的設(shè)計(jì)。MVC設(shè)計(jì)模式由三部分組成。模型是應(yīng)用對象,沒有用戶界面。視圖表示它在屏幕上的顯示,代表流向用戶的數(shù)據(jù)。控制器定義用戶界面對用戶輸入的響應(yīng)方式,負(fù)責(zé)把用戶的動(dòng)作轉(zhuǎn)成針對Model的操作。Model 通過更新View的數(shù)據(jù)來反映數(shù)據(jù)的變化。
            三者關(guān)系如圖:


            對MVC關(guān)系圖的理解

            圖2 MVC的分工與協(xié)作

            2. MVC中的設(shè)計(jì)模式
            一個(gè)以MVC為架構(gòu)的系統(tǒng)包含了很多的設(shè)計(jì)模式,但是與MVC最為密切相關(guān)的是下面三種模式:Observer, Composite和Strategy。
            2.1 Observer模式
            MVC通過使用定購/通知的方式分離了Model和View。View要保證自己顯示能正確地反映出Model的內(nèi)容和狀態(tài)。一旦Model的內(nèi)容發(fā)生變化,必須有一個(gè)機(jī)制來使得Model能夠通知相關(guān)的View,使得相關(guān)的View可以在適當(dāng)?shù)臅r(shí)機(jī)刷新數(shù)據(jù)。這個(gè)設(shè)計(jì)還可以解決更一般的問題,將對象分離,使得一個(gè)對象的改變能夠影響到另一些對象,而這個(gè)對象并不知道那些被影響的對象的細(xì)節(jié)。這就是被描述為Observer的設(shè)計(jì)模式。
            模式類型:Observer模式是對象型模式,同時(shí)它也是行為型模式。
            模式目的:定義對象間的一對多的依賴關(guān)系,當(dāng)一個(gè)對象的值或狀態(tài)發(fā)生改變時(shí),所有與它有依賴關(guān)系的對象都得到通知并自動(dòng)更新。某一數(shù)據(jù)可能有多種顯示方式,并且可能同時(shí)以不同的方式顯示(如圖2)。當(dāng)通過某一種方式改變了數(shù)據(jù),那么其他的顯示都應(yīng)該能立即知道數(shù)據(jù)的改變和做相應(yīng)的調(diào)整。
            模式結(jié)構(gòu):

            圖 3. Observer模式的結(jié)構(gòu)圖

            效果:
            1. 抽象耦合。目標(biāo)對象只知道它有一些觀察者,每個(gè)觀察者都符合抽象的Observer類的簡單接口,并不知道它們具體屬于哪個(gè)類。這樣使得目標(biāo)和觀察者之間的耦合最小且抽象。
            2. 支持廣播通信。目標(biāo)發(fā)送通知不用指定觀察者,如何處理通知由觀察者決定。
            3. 可能的意外更新。要處理好更新邏輯,避免錯(cuò)誤更新。

            2.2 Composite模式
            MVC的一個(gè)重要特征就是View可以嵌套。嵌套的組合視圖可用于任何視圖可用的地方,而且可以管理嵌套視圖。這種思想反映出將組合的視圖與其組件平等對待的設(shè)計(jì)。這種設(shè)計(jì)思想在面向?qū)ο箢I(lǐng)域內(nèi)被描述成為Composite的設(shè)計(jì)模式。
            模式類型:Composite模式是對象型模式,同時(shí)它也是結(jié)構(gòu)型模式。
            模式目的:將對象組合成樹形結(jié)構(gòu)以表示"部分-整體"層次結(jié)構(gòu)。Composite使組合對象的使用和單個(gè)對象的使用具有一致性。
            模式結(jié)構(gòu):

            圖4. Composite模式的結(jié)構(gòu)圖
            效果:
            1. 定義了包含簡單對象和組合對象的類層次結(jié)構(gòu)。簡單對象可以被組合到復(fù)雜對象中,而組合的對象可以再被組合。這樣客戶端代碼中用到簡單對象的地方都可以使用組合對象。
            2. 簡化客戶端代碼。客戶端不用知道某對象是簡單對象還是組合對象,可以以一致的方式使用這些對象。
            3. 更容易增加新類型的組件。新的組件可以方便地加入已有組合對象中不用改變客戶端代碼。

            2.3 Strategy模式
            MVC的另一重要特征是可以在不改變View的情況下改變View對用戶輸入的響應(yīng)方式。這對一個(gè)經(jīng)常需要變更響應(yīng)邏輯的系統(tǒng)來說是非常重要的。MVC把響應(yīng)邏輯封裝在Controller中。有一個(gè)Controller的類層次結(jié)構(gòu),可以方便地對原有Controller做適當(dāng)改變,創(chuàng)建新的Controller。View使用Controller子類的實(shí)例來實(shí)現(xiàn)一個(gè)特定的響應(yīng)策略。要實(shí)現(xiàn)不同的響應(yīng)策略,只要用不同種類的Controller實(shí)例替換即可。還可以在運(yùn)行時(shí)刻通過改變View的Controller來改變View對用戶輸入的響應(yīng)策略。這種View-Controller的關(guān)系是被描述為Strategy的設(shè)計(jì)模式的一個(gè)例子。
            模式類型:Strategy模式是對象型模式,同時(shí)它也是行為型模式。
            模式目的:定義一系列的算法,并且把它們封裝起來,使它們可以互相替換,使得算法可以獨(dú)立于使用它的客戶端而變化。
            模式結(jié)構(gòu):

            圖5. Strategy模式的結(jié)構(gòu)圖

            效果:
            1. Strategy類層次為Context定義了可重用的相關(guān)算法或行為。
            2. 替代繼承的方法。如果直接繼承Context,給以不同的行為,會(huì)將行為加到Context中,從而將算法的實(shí)現(xiàn)與Context混合起來,使Context難以理解,維護(hù)和擴(kuò)展,而且不能動(dòng)態(tài)地改變算法。將算法封裝在獨(dú)立的Strategy類,可以使得算法獨(dú)立于Context改變,容易切換擴(kuò)展。
            3. 可以提供相同行為的不同實(shí)現(xiàn)。
            4. 客戶端必須了解Strategy之間有何不同。
            5. Context和Strategy之間的通信開銷。
            6. 增加了對象的數(shù)目。

            3. MVC在 Web系統(tǒng)中的應(yīng)用
            現(xiàn)在的一些基于Web的分布式系統(tǒng)如B2B電子商務(wù)系統(tǒng),就適合采用MVC架構(gòu)。
            通過分析,從高層次的角度可以將一個(gè)應(yīng)用的對象分為三類。一類就是負(fù)責(zé)顯示的對象,一類對象包含商業(yè)規(guī)則和數(shù)據(jù),還有一類就是接收請求,控制商業(yè)對象去完成請求。這些應(yīng)用的顯示是經(jīng)常需要變換的,如網(wǎng)頁的風(fēng)格,色調(diào),還有需要顯示的內(nèi)容,內(nèi)容的顯示方式等。而商業(yè)規(guī)則和數(shù)據(jù)是相對要穩(wěn)定的。因此,表示顯示的對象View經(jīng)常需要變化的,表示商業(yè)規(guī)則和數(shù)據(jù)的對象Model要相對穩(wěn)定,而表示控制的Controller則最穩(wěn)定。
            通常當(dāng)系統(tǒng)發(fā)布后,View對象是由美工,HTML/JSP設(shè)計(jì)人員或者系統(tǒng)管理員來負(fù)責(zé)管理的。Controller對象由應(yīng)用開發(fā)人員開發(fā)實(shí)施,商業(yè)規(guī)則對象和商業(yè)數(shù)據(jù)對象則由開發(fā)人員,領(lǐng)域?qū)<液蛿?shù)據(jù)庫管理員共同完成的。顯示邏輯在Web層或客戶端控制,可以是Servlet 或JSP,動(dòng)態(tài)地生成Html。一般來說采用JSP要比采用Servlet要好。JSP更好地將代碼與Html部分分開,有利于頁面設(shè)計(jì)人員和代碼開發(fā)人員的分離,提高效率。同時(shí)JSP可以完成所有Servlet完成的功能,實(shí)際上JSP最終也轉(zhuǎn)換成一個(gè)Servlet。與控制有關(guān)的對象存在于系統(tǒng)的每一個(gè)層次,協(xié)調(diào)跨層動(dòng)作。包含商業(yè)規(guī)則和數(shù)據(jù)的對象存在于EJB層(以EJB為中心的模式)或Web層(以Web為中心的模式)。

            3.1 View在Web系統(tǒng)中的應(yīng)用
            View代表系統(tǒng)的顯示,它完全存在于Web層。一般由JSP, Java Bean和Custom Tag組成。JSP可以動(dòng)態(tài)生成網(wǎng)頁內(nèi)容,Custom Tag 更方便了使用Java Bean,而且它可以封裝顯示邏輯,更有利于于模塊化和重用。一些設(shè)計(jì)良好的Custom Tag可以在多個(gè)JSP甚至可以在不同的系統(tǒng)里重復(fù)使用。Java Bean用來控制JSP和Model對象。JSP通過Java Bean 來讀取Model對象中的數(shù)據(jù),Model和Controller對象則負(fù)責(zé)對Java Bean的數(shù)據(jù)更新。一般來說,可以先要設(shè)計(jì)出所有可能出現(xiàn)的屏幕,即用戶使用系統(tǒng)時(shí)可以看到的所有內(nèi)容。然后根據(jù)這些內(nèi)容,找出公共部分,靜態(tài)部分和動(dòng)態(tài)變化部分。可以考慮使用模板方法,把公用的內(nèi)容單獨(dú)生成JSP,需要變化的也各自生成Html或JSP, 由一個(gè)模板JSP, 把這些不同部分動(dòng)態(tài)地引入(include方法)。還有一個(gè)要考慮的問題就是屏幕的選擇問題,當(dāng)處理完用戶請求,模板被自動(dòng)調(diào)用來顯示,這個(gè)顯示一定要知道用戶關(guān)心的屏幕是有哪些部分組成。所以可以考慮把所有屏幕的定義放在一個(gè)集中的文件里,如一個(gè)java文件或文本文件。由于考慮到屏幕定義文件將來的變更可能性,最好使用文本文件如一個(gè)XML文件,這樣將來更改不用重新編譯。可以根據(jù)用戶輸入的URL和參數(shù)可以映射到某一個(gè)結(jié)果屏幕,當(dāng)然有可能還要根據(jù)動(dòng)作的執(zhí)行結(jié)果選擇不同的結(jié)果屏幕內(nèi)容。所以需要一個(gè)請求與資源的匹配文件(XML),如果一個(gè)URL請求有幾種不同結(jié)果,則要在該文件中指明是否需要流控制(一種controller對象)以及不同流向的對應(yīng)屏幕。

            3.2 Model在Web系統(tǒng)中的應(yīng)用

            Model對象代表了商業(yè)規(guī)則和商業(yè)數(shù)據(jù),存在于EJB層和Web層。在J2EE的規(guī)范中,系統(tǒng)有些數(shù)據(jù)需要存儲(chǔ)于數(shù)據(jù)庫中,如用戶的賬號(hào)信息(account model),公司的數(shù)據(jù)(company model)等,也有一些不需要記錄在數(shù)據(jù)庫里的,如某用戶瀏覽的當(dāng)前產(chǎn)品目錄(catalog model),他的購物內(nèi)容(shopping cart model)等。這些model數(shù)據(jù)存在于哪一層要根據(jù)它們的生命周期和范圍來決定。在Web層有HttpSession和ServletContext及Java Bean對象來存儲(chǔ)數(shù)據(jù),在EJB層則有EJB來存儲(chǔ)數(shù)據(jù)和邏輯。Web層的Java Bean的model對象存儲(chǔ)了EJB層model對象的數(shù)據(jù)的拷貝。因?yàn)镋JB層有很多不同的model對象,所以Web層可以通過一個(gè)ModelManager來控制EJB層的各model對象,在ModelManger中可以封裝使用后臺(tái)model對象的方法。
            在EJB層把所有的數(shù)據(jù)和規(guī)則都模式化為EJB也是不恰當(dāng)?shù)摹H缈梢园汛嫒?shù)據(jù)庫的對象模式化為DAO對象。DAO中可以封裝與具體數(shù)據(jù)庫的交互細(xì)節(jié),如可以讀寫不同的表,多個(gè)數(shù)據(jù)庫,甚至多種數(shù)據(jù)庫。如定單的model對象可以是一個(gè)OrderDAO, 它可能要同時(shí)處理Order表,OrderStatus表和OrderItemLines表。
            還有可以考慮使用Value對象。一個(gè)Value 對象可以封裝遠(yuǎn)程對象,因?yàn)槊恳粋€(gè)讀遠(yuǎn)程對象的屬性都可能是一個(gè)遠(yuǎn)程過程調(diào)用,都會(huì)耗費(fèi)網(wǎng)絡(luò)資源。可以在EJB的遠(yuǎn)程對象中使用Value對象. 在遠(yuǎn)程對象中一次性得到Value對象來得到所有屬性的值。

            3.3 Controller在Web系統(tǒng)中的應(yīng)用
            Controller對象協(xié)調(diào)Model與View,把用戶請求翻譯成系統(tǒng)識(shí)別的事件。在Web層,一般有一個(gè)MainServlet(或Main.jsp),接收所有請求,它可以調(diào)用屏幕流管理器(ScreenFlowManger)決定下一個(gè)屏幕。一般還有一個(gè)請求處理器RequestProcessor,包含所有請求都需要做的處理邏輯,如把請求翻譯成系統(tǒng)事件(RequestToEvent)。請求處理器通常還包含一個(gè)代理對象ClientControlWebImpl,它是EJB層的邏輯處理的在Web層的代理。在EJB層,有一個(gè)ClientController提供Web 層對EJB層的只讀訪問。還有一個(gè)StateMachine用來建立和刪除ejb,處理Web層送來的事件。
            Controller還有一個(gè)重要的功能就是同步View和Model的數(shù)據(jù)。在ModelManger中包含一個(gè)ModelUpdateManger,它把系統(tǒng)事件轉(zhuǎn)換為一個(gè)Model的集合,即所有需要同步的Model,然后通知Listeners去做同步操作。

            4. 結(jié)束語
            近年來隨著互聯(lián)網(wǎng)技術(shù)的發(fā)展和新的商業(yè)模式的出現(xiàn),必然會(huì)出現(xiàn)大量基于Web的應(yīng)用系統(tǒng)。對于如何設(shè)計(jì)這些系統(tǒng)的體系結(jié)構(gòu),也逐漸有了一些統(tǒng)一的認(rèn)識(shí),最主要的是的就是其體系結(jié)構(gòu)要合理,開放。需求永遠(yuǎn)會(huì)比技術(shù)和設(shè)計(jì)思想發(fā)展快,要使將來系統(tǒng)的升級(jí)所付出的代價(jià)最小,研究軟件系統(tǒng)的體系結(jié)構(gòu)還是非常很用和有必要的。

            參考文獻(xiàn)
            [1] 設(shè)計(jì)模式,作者Erich Gamma 等,ISBN 7-111-07575-7, 機(jī)械工業(yè)出版社 2000.9
            [2] Core J2EE Patterns, 作者Deepak Alurm 等, ISBN 0-13-064884-1, Sun Microsystems Inc, 2001年
            [3] Designing Enterprise Applications with the J2EETM Platform, 作者Nicholas Kassem 等, Sun Microsystems, Inc. 2000年

            posted @ 2007-05-15 09:12 colys 閱讀(488) | 評論 (0)編輯 收藏

            2007年4月22日 #

            題目:

            有十個(gè)開關(guān)等間距排成一線,每個(gè)開關(guān)對應(yīng)其上方的一盞燈(十盞燈也排成一線)。每按動(dòng)一下開關(guān),可以使對應(yīng)的燈改變狀態(tài)(原來亮著的將熄滅,原來熄滅的將被點(diǎn)亮)。
            但是,由于開關(guān)之間的距離很小,每次按動(dòng)開關(guān)時(shí),相鄰的一個(gè)開關(guān)也將被按動(dòng)。例如:按動(dòng)第5個(gè)開關(guān),則實(shí)際上第4、5、6個(gè)開關(guān)都被按動(dòng)。而按動(dòng)靠邊的第1個(gè)開關(guān)時(shí),第1、2個(gè)開關(guān)都被按動(dòng)。并且,無法只按動(dòng)最靠邊的一個(gè)開關(guān)。
            現(xiàn)在給出十盞燈的初始的狀態(tài)和目標(biāo)狀態(tài),要求計(jì)算:從初始狀態(tài)改變到目標(biāo)狀態(tài)所需要的最少操作次數(shù)。
            函數(shù)接口:
            int MinChange(const int Start[],const int End[]);
            其中:Start表示了初始狀態(tài),End表示了目標(biāo)狀態(tài)。表示狀態(tài)的數(shù)組(Start和End)中,若某元素為0表示對應(yīng)的燈亮著,否則表示對應(yīng)的燈沒有亮。調(diào)用函數(shù)時(shí)保證Start和End數(shù)組長度均為10,并保證有解。

            看了很多人的解法都是用循環(huán)遍歷來判斷是否達(dá)到最后要求,但是如果和線形代數(shù)結(jié)合的話,就有一種很快速的解法。

            約定:以下所用的‘+’號(hào)都是‘異或’的運(yùn)算。
            先簡化一下,假設(shè)有四個(gè)燈,初始狀態(tài)s0~s3,目標(biāo)狀態(tài)是e0~e3,轉(zhuǎn)換一次狀態(tài)就是和1進(jìn)行異或運(yùn)算一次,所以狀態(tài)轉(zhuǎn)移矩陣為:
            (s0,s1,s2,s3)+k0*(1,1,0,0)+k1*(1,1,1,0)+k2*(0,1,1,1)+k3*(0,0,1,1)=(e0,e1,e2,e3);
            其中k(n)表示第n個(gè)開關(guān)所翻動(dòng)的次數(shù)。并且,注意異或運(yùn)算中a+b+b=a,所以,某個(gè)開關(guān)翻動(dòng)偶數(shù)次的效果相當(dāng)于沒有翻動(dòng),翻動(dòng)奇數(shù)次的效果相當(dāng)于翻動(dòng)一次;又由于異或運(yùn)算滿足交換律,所以翻動(dòng)的順序沒有影響。綜上每個(gè)開關(guān)翻動(dòng)的次數(shù)只有1次或0次就足夠了。

            設(shè)m(n)=s(n)+e(n),注意異或運(yùn)算中的'-'也就是'+',所以解線性方程組:
            k0+k1      =m1;
            k0+k1+k2   =m2;
               k1+k2+k3=m3;
                  k2+k3=m4;
            假設(shè)解存在,就可以算出通解(k0,k1,k2,k3),再統(tǒng)計(jì)出通解中1的個(gè)數(shù),就是所需要翻動(dòng)的次數(shù)了。并且還可以知道哪些開關(guān)需要撥動(dòng),比如算出解是(1,0,1,0)就是第0和2個(gè)開關(guān)需要撥動(dòng)一次。

            因此針對本題目的10個(gè)燈泡,本人已算出這10元線性方程組的通解:
            k0=m0+m2+m3+m5+m6+m8+m9;
            k1=m2+m3+m5+m6+m8+m9;
            k2=m0+m1;
            k3=m3+m0+m1+m5+m6+m8+m9;
            k4=m5+m6+m8+m9;
            k5=m4+m3+m0+m1;
            k6=m6+m4+m3+m0+m1+m8+m9;
            k7=m8+m9;
            k8=m7+m6+m4+m3+m0+m1;
            k9=m9+m7+m6+m4+m3+m0+m1;

            和上面一樣,m(n)為開始狀態(tài)與目標(biāo)狀態(tài)的每位異或。至于是否存在解,本人已將次系數(shù)矩陣化簡為對角矩陣,可以看到系數(shù)矩陣的秩(Rank)與未知數(shù)的個(gè)數(shù)相等,所以無論是任何的輸入和輸出變換都能找到唯一解。

            本人程序如下:
            int MinChange(const int Start[],const int End[]){
                int m[10];
                int k[10];
                int res=0;
                int i,j,n;
                for(i=0;i<10;i++){
                        m[i]=Start[i]^End[i];  /* m[]=Start[] XOR End[] */
                    }
                /* calculate roots */
                k[0]=m[0]^m[2]^m[3]^m[5]^m[6]^m[8]^m[9];
                k[1]=m[2]^m[3]^m[5]^m[6]^m[8]^m[9];
                k[2]=m[0]^m[1];
                k[3]=m[3]^m[0]^m[1]^m[5]^m[6]^m[8]^m[9];
                k[4]=m[5]^m[6]^m[8]^m[9];
                k[5]=m[4]^m[3]^m[0]^m[1];
                k[6]=m[6]^m[4]^m[3]^m[0]^m[1]^m[8]^m[9];
                k[7]=m[8]^m[9];
                k[8]=m[7]^m[6]^m[4]^m[3]^m[0]^m[1];
                k[9]=m[9]^m[7]^m[6]^m[4]^m[3]^m[0]^m[1];
                /* count for switch times */
                for(j=0;j<10;j++){
                    if(k[j]) res++;
                    }
                /* display k(n); */
                for(n=0;n<10;n++) printf("%d,",k[n]);
                return res;
            }

            測試主程序:
            main(){
                int A[10]={1,1,1,0,0,1,0,1,1,0};
                int B[10]={0,0,1,1,0,0,1,1,1,1};
                int C;
                C=MinChange(A,B);
                printf("**%d**",C);
            }
            顯示結(jié)果為:
            1,0,0,0,1,1,1,1,0,1,**6**
            就是如果要把狀態(tài)A轉(zhuǎn)為狀態(tài)B,需要把第0,4,5,6,7,9號(hào)開關(guān)翻動(dòng)一次,共6次。
            測試驗(yàn)證結(jié)果正確:)

            當(dāng)然,此做法也有一個(gè)缺點(diǎn),就是當(dāng)燈的個(gè)數(shù)改變時(shí),就要重新設(shè)定線形方程組的特解形式。


            posted @ 2007-04-22 10:02 colys 閱讀(366) | 評論 (1)編輯 收藏



            l 初始化
            ² 當(dāng)頁面被提交請求第一個(gè)方法永遠(yuǎn)是構(gòu)造函數(shù)。您可以在構(gòu)造函數(shù)里面初始一些自定義屬性或?qū)ο螅贿^這時(shí)候因 為頁面還沒有被完全初始化所以多少會(huì)有些限制。特別地,您需要使用HttpContext對象。當(dāng)前可以使用的對象包括QueryString, Form以及Cookies集合,還有Cache對象。注意:在構(gòu)造函數(shù)里是不允許使用Session的。

            ² 下一個(gè)將執(zhí)行的方法是AddParsedSubObject方法,這個(gè)方法將添加所有獨(dú)立的控件并把頁面組成一個(gè)控件集合樹,這個(gè)方 法經(jīng)常被一些高級(jí)的頁面模板解決方案(Page Template Solutions)重寫以便添加頁面內(nèi)容到頁面模板(Page Template)中一些特殊的控件中。這個(gè)方法遞歸應(yīng)用到所有的頁面控件及相應(yīng)的的每個(gè)子控件,所有的控件都是在這個(gè)方法中開始最早的初始化。

            ² 頁面類中下一個(gè)將執(zhí)行的方法是DeterminePostBackMode。這個(gè)方法允許您修改IsPostBack的值及相關(guān)的事件。如果您 需要從數(shù)據(jù)庫中加載ViewState這個(gè)方法將特別有用,因?yàn)閂iewState只有在IsPostBack為真的情況下才會(huì)進(jìn)行恢復(fù)。返回空將會(huì)導(dǎo)致 強(qiáng)制執(zhí)行非回傳,返回Request.Form則強(qiáng)制執(zhí)行一個(gè)回傳。除非在特殊情況下,否則并不建議去操作這個(gè),因?yàn)檫@個(gè)還會(huì)影響其他的事件。

            ² 下一個(gè)將要執(zhí)行的方法是OnInit方法,一般這是第一個(gè)真正被使用的方法。這個(gè)方法觸發(fā)時(shí),所有頁面定義中的控件執(zhí)行初始化,這意味著所有在 頁面中定義的值應(yīng)用到相應(yīng)的控件上。不過,ViewState和傳回的值還不會(huì)應(yīng)用到控件上,因此,任何被代碼或用戶改變的值還沒有被恢復(fù)到控件上。這個(gè) 方法通常是最好的創(chuàng)建、重創(chuàng)建動(dòng)態(tài)控件的好地方。
            l 恢復(fù)及加載
            ² 下一個(gè)方法, LoadPageStateFromPersistenceMedium只會(huì)在頁面被回傳的時(shí)候才會(huì)被執(zhí)行。如果因?yàn)槭褂肧ession或自定義存儲(chǔ)方 式,您修改了后面將要提到的影響ViewState保存方式的方法SavePageStateToPersistenceMedium,則這個(gè)方法需要被 重寫。默認(rèn)的實(shí)現(xiàn)中ViewState是一種Base64格式編碼,并且被保存在頁面的隱藏域中,您可以使用這篇文章中提及的方法修改ViewState 按以上兩種方式保存。注意:這個(gè)方法并沒有真正加載ViewState到頁面或頁面控件中。

            ² 當(dāng)?shù)玫絍iewState后,下一個(gè)方法LoadViewSate,將以遞歸的方式恢復(fù)ViewState到頁面及各個(gè)頁面控件或子控件中。這 個(gè)方法執(zhí)行后,每個(gè)控件都將恢復(fù)到上一次的狀態(tài),但是用戶提交的數(shù)據(jù)還沒有應(yīng)用到控件上,因?yàn)樗麄儾皇荲iewState的一部分。這個(gè)方法主要用于恢復(fù) 您在其他事件中動(dòng)態(tài)生成的控件的值,他們的值是您手動(dòng)保存在ViewSate中,并且現(xiàn)在已經(jīng)失效。

            ² 下一個(gè)方法是ProcessPostData,這個(gè)方法也同樣是回傳的時(shí)候才會(huì)被執(zhí)行,并且不允許被重寫,這個(gè)是頁面基類的私有方法。這個(gè)方法 通過匹配控件的名稱恢復(fù)相應(yīng)的用戶提交的控件的值,到這一步意味著整個(gè)頁面都已經(jīng)被完全恢復(fù)了。唯一要記住的是所有動(dòng)態(tài)控件的創(chuàng)建必須在這個(gè)方法之前。這 個(gè)方法也是記錄后面的改變事件的方法。

            ² 下一個(gè)方法是OnLoad方法,通常這是用得最多的方法,因?yàn)檫@個(gè)方法是頁面生存期第一個(gè)恢復(fù)了所有值的地方。大多數(shù)代碼根據(jù)判斷 IsPostBack來決定是否重新設(shè)置控件狀態(tài)。您也可以在這個(gè)方法中調(diào)用Validate并且檢查IsValid的值。也可以在這個(gè)方法中創(chuàng)建動(dòng)態(tài)控 件,并且該控件的所有的方法都會(huì)被執(zhí)行以追上當(dāng)前頁面的狀態(tài)包括ViewSate,不過不包括回傳的值。
            l 事件處理
            ² 下一個(gè)方法還是 ProcessPostData,實(shí)際上就是前一個(gè)方法的另一次調(diào)用,它仍然是只在回傳的時(shí)候執(zhí)行并且由于是私有方法不可以被重寫。如果您是第一次看頁面 的運(yùn)行軌跡也許會(huì)覺得這個(gè)方法有些多余。但實(shí)際上這個(gè)方法是必要的因?yàn)樵贠nLoad中創(chuàng)建的動(dòng)態(tài)控件也需要他們回傳的值。任何在這以后創(chuàng)建的控件將可以 得到他們的ViewState,但是不能再得到他們的回傳的值,并且不會(huì)觸發(fā)任何值改變事件(Change Event)。

            ² 下一個(gè)方法,RaiseChangedEvents,也是只在回傳頁面中執(zhí)行,并且也因?yàn)槭腔惖乃接蟹椒ㄋ胁荒鼙焕^承。在整個(gè)頁面生存期 中,是在這兒根據(jù)之前的ProcessPostData記錄的控件的值和提交的值是否不同來觸發(fā)值改變事件。您也許需要調(diào)用Validate或者檢查 IsValid的值。這里并沒有特別的說明多個(gè)值改變事件的執(zhí)行先后順序。

            ² 下一個(gè)方法,RaisePostBackEvent,同樣是因?yàn)槭腔惖乃接蟹椒ú荒鼙焕^承,同樣也是只在回傳頁面中執(zhí)行。除非使用了 AutoPostBack,不然這是實(shí)際提交表單事件執(zhí)行的地方,特別是按鈕或者其實(shí)使用javascript提交表單等。如果還沒有被手動(dòng)調(diào)用過并且使 用了驗(yàn)證控件,那么Validate會(huì)被調(diào)用。注意IE中有個(gè)BUG有時(shí)會(huì)允許提交但卻不觸發(fā)任何事件。

            ² 下一個(gè)方法是OnPreRender,一般這是在客戶端展現(xiàn)頁面之前改變頁面及其控件的最后一次機(jī)會(huì)。您也可以在這個(gè)方法里面創(chuàng)建動(dòng)態(tài)控件,并 且所有的方法都會(huì)被執(zhí)行以追上當(dāng)前頁面的狀態(tài)包括ViewSate,但是私有方法將不會(huì)被執(zhí)行,這意味著不會(huì)有回傳的值并且不會(huì)有事件觸發(fā)。由于IE中的 BUG,這是一個(gè)沒有事件趕上PostBack的好地方。
            l 保存及顯示
            ² 下一個(gè)方法是SaveViewState,不論是否是回傳頁 面,均會(huì)遞歸的執(zhí)行以保存頁面及其所有控件的ViewState。ViewState基本上保存所有與定義在aspx中的原始值不同的值,不管是被代碼還 是用戶所改變。注意控件值是根據(jù)他們在頁面的控件樹中的位置來保存的,所以如果動(dòng)態(tài)控件后來加到了錯(cuò)誤的位置將會(huì)導(dǎo)致混亂。

            ² 下一個(gè)方法是SavePageStateToPersistenceMedium真正的保存頁面的ViewSate。這個(gè)方法隨同 LoadPageStateFromPersistenceMediumg 一起被重寫以便保存ViewState到Session或其它自定義數(shù)據(jù),而不是用隱藏域。這對于低帶寬的用戶來說是很有幫助的。并且對于移動(dòng)設(shè)備來說, Session是默認(rèn)設(shè)置。下面這篇文章描述了使用以上兩種方式保存ViewState的具體細(xì)節(jié)。注意在Asp.net中有個(gè)Bug:Asp.net要 求必須提交__viewstate字段,即使是空的。

            ² 下一個(gè)方法是Render方法,該方法遞歸的創(chuàng)建并發(fā)送相應(yīng)控件的html給瀏覽器。這個(gè)方法被一些頁面模板方案重寫以添加一些通用的頁面頭與 腳而不使用服務(wù)器控件,他們總是有一些額外的東西。注意這兒的修改只能使用純HTML,因?yàn)榭丶谶@兒已經(jīng)被生成了。您可以用 StringBuilder,StringWriter,HtmlTextWriter捕獲相應(yīng)的HTML輸出。

            ² 最后的方法是OnUnload,這個(gè)方法會(huì)調(diào)用相應(yīng)的Dispose方法。這個(gè)方法提供機(jī)會(huì)以便清空該頁面中使用的非托管資源,如關(guān)閉打開的文 件句柄,以前打開的數(shù)據(jù)庫連接等。注意這個(gè)方法是在頁面已經(jīng)發(fā)送到客戶端以后執(zhí)行的,所以它只有影響服務(wù)器對象,并且它不會(huì)顯示在頁面的顯示軌跡中。這就 是頁面的生存期,對于每一次請求都是這么運(yùn)行的。
            l 作者簡介(略)

            表1:頁面事件總結(jié)


            方法回傳控件


            ConstructorAlwaysAll
            AddParsedSubObjectAlwaysAll
            DeterminePostBackModeAlwaysPage
            OnInitAlwaysAll


            LoadPageStateFromPersistenceMediumPostBackPage
            LoadViewStatePostBackAll
            ProcessPostData1PostBackPage
            OnLoadAlwaysAll


            ProcessPostData2PostBackPage
            RaiseChangedEventsPostBackPage
            RaisePostBackEventPostBackPage
            OnPreRenderAlwaysAll


            SaveViewStateAlwaysAll
            SavePageStateToPersistenceMediumAlwaysPage
            RenderAlwaysAll
            OnUnloadAlwaysAll

            posted @ 2007-04-22 09:27 colys 閱讀(551) | 評論 (1)編輯 收藏

            2007年3月19日 #

            1.神要是公然去跟人作對,那是任何人都難以對付的。 (《荷馬史詩》)

            2.生存還是毀滅,這是一個(gè)值得思考的問題。 (《哈姆霄特》)

            3.善良人在追求中縱然迷惘,卻終將意識(shí)到有一條正途。(《浮士德》)

            4.認(rèn)識(shí)自己的無知是認(rèn)識(shí)世界的最可靠的方法。 (《隨筆集》)

            5.你以為我貧窮、相貌平平就沒有感情嗎?我向你發(fā)誓,如果上帝賦予我財(cái)富和美貌,我會(huì)讓你無法離開我,就像我現(xiàn)在無法離開你一樣。雖然上帝沒有這么做,可我們在精神上依然是平等的。(《簡?愛》)

            6.大人都學(xué)壞了,上帝正考驗(yàn)他們呢,你還沒有受考驗(yàn),你應(yīng)當(dāng)照著孩子的想法生活。 (《童年》)

            7,你越?jīng)]有心肝,就越高升得快,你毫不留情地打擊人家,人家就怕你。只能把男男女女當(dāng)作驛馬,把它們騎得筋疲力盡,到了站上丟下來,這樣你就能達(dá)到欲望的最高峰。 (《高老頭》)

            8.我只想證明一件事,就是,那時(shí)魔鬼引誘我,后來又告訴我,說我沒有權(quán)利走那條路,因?yàn)槲也贿^是個(gè)虱子,和所有其余的人一樣。 (《罪與罰》)

            9.你瞧,桑丘?潘沙朋友,那邊出現(xiàn)了三十多個(gè)大得出奇的巨人。 (《堂?吉訶德》)

            10.我并不愿意你受的苦比我受的還大,希斯克利夫。我只愿我們永遠(yuǎn)不分離:如果我有一句話使你今后難過,想想我在地下也感到一樣的難過,看在我自己的份上,饒恕我吧! (《呼嘯山莊》)

            11.幸福的家庭是相同的,不幸的家庭各有各的不同。 (《安娜?卡列尼娜》)

            12.唉,奴隸般的意大利,你哀痛之逆旅,你這暴風(fēng)雨中沒有舵手的孤舟,你不再是各省的主婦,而是妓院! (《神曲》)

            13.將感情埋藏得太深有時(shí)是件壞事。如果一個(gè)女人掩飾了對自己所愛的男子的感情,她也許就失去了得到他的機(jī)會(huì)。 (《傲慢與偏見》)

            14.鐘聲又鳴響了……一聲又一聲,靜謐而安詳,即使在女人做新娘的那個(gè)好月份里,鐘聲里也總帶有秋天的味道。 (《喧囂與騷動(dòng)》)

            15.一個(gè)人并不是生來要被打敗的,你盡可以把他消滅掉,可就是打不敗他。 (《老人與海》)

               16.當(dāng)然,行是行的,這固然很好,可是千萬別鬧出什么亂子來啊。 (《套中人》)

               17.面包!面包!我們要面包! (《萌芽》)

               18.我從沒有愛過這世界,它對我也一樣。 (《拜倫詩選》)

            19.  愛情應(yīng)該給人一種自由感,而不是囚禁感。 (《兒子與情人》)

               20.暴風(fēng)雨將要在那一天,甚至把一些槲樹吹倒,一些教堂的高塔要倒塌,一些宮殿也將要?jiǎng)訐u! (《海涅詩選》)

               21.自己的行為最惹人恥笑的人,卻永遠(yuǎn)是最先去說別人壞話的人。 (《偽君子》)

               22.這時(shí)一種精神上的感慨油然而生,認(rèn)為人生是由啜泣、抽噎和微笑組成的,而抽噎占了其中絕大部分。(《歐?亨利短篇小說選》)

               23.歷史喜愛英勇豪邁的事跡,同時(shí)也譴責(zé)這種事跡所造成的后果。 (《神秘島》)

               24.整個(gè)下半天,人都聽?wèi){羊脂球去思索。不過本來一直稱呼她作“夫人”,現(xiàn)在卻簡單地稱呼她作“小姐”了,誰也不很知道這是為著什么,仿 佛她從前在評價(jià)當(dāng)中爬到了某種地位,現(xiàn)在呢,人都想把她從那種地位拉下一級(jí)似的,使她明白自己的地位是尚叩摹?(《莫泊桑短篇小說選》)

            25.如果冬天來了,春天還會(huì)遠(yuǎn)嗎?  (《雪萊詩選》)

               26.我明白了,我已經(jīng)找到了存在的答案,我惡心的答案,我整個(gè)生命的答案。其實(shí),我所理解的一切事物都可以歸結(jié)為荒誕這個(gè)根本的東西。(《惡心》)

               27.世界上有這樣一些幸福的人,他們把自己的痛苦化作他人的幸福,他們揮淚埋葬了自己在塵世間的希望,它卻變成了種子,長出鮮花和香膏,為孤苦伶仃的苦命人醫(yī)治創(chuàng)傷。(《湯姆叔叔的小屋》)

               28.當(dāng)格里高?薩姆莎從煩躁不安的夢中醒來時(shí),發(fā)現(xiàn)他在床上變成了一個(gè)巨大的跳蚤。(《變形記》)

               29.當(dāng)現(xiàn)實(shí)折過來嚴(yán)絲合縫地貼在我們長期的夢想上時(shí),它蓋住了夢想,與它混為一體,如同兩個(gè)同樣的圖形重疊起來合而為一一樣。(《追憶似水年華》)

               30.人與人之間,最可痛心的事莫過于在你認(rèn)為理應(yīng)獲得善意和友誼的地方,卻遭受了煩擾和損害。(《巨人傳》)

               31.現(xiàn)在我說的您要特別注意聽:在別人心中存在的人,就是這個(gè)人的靈魂。這才是您本身,才是您的意識(shí)在一生當(dāng)中賴以呼吸、營養(yǎng)以至陶醉的東西,這也就是您的靈魂、您的不朽和存在于別人身上的您的生命。(《日瓦戈醫(yī)生》)

               32.美德猶如名香,經(jīng)燃燒或壓榨而其香愈烈,蓋幸運(yùn)最能顯露惡德而厄運(yùn)最能顯露美德。(《培根論說文集》)

               33.親愛的艾妮斯,我出國,為了愛你,我留在國外,為了愛你,我回國,也是為了愛你!(《大衛(wèi)?科波菲爾》)

               34.強(qiáng)迫經(jīng)常使熱戀的人更加鐵心,而從來不能叫他們回心轉(zhuǎn)意。(《陰謀與愛情》)

            35.在各種事物的常理中,愛情是無法改變和阻擋的,因?yàn)榫捅拘远裕瑦壑粫?huì)自行消亡,任何計(jì)謀都難以使它逆轉(zhuǎn)。(《十日談》)

               36.只要你是天鵝蛋,就是生在養(yǎng)雞場里也沒有什么關(guān)系。(《安徒生童話》)

               37.就投機(jī)鉆營來說,世故的價(jià)值永遠(yuǎn)是無可比擬的。(《死魂靈》)

               38. 誰都可能出個(gè)錯(cuò)兒,你在一件事情上越琢磨得多就越容易出錯(cuò)。(《好兵帥克歷險(xiǎn)記》)

               39.我們經(jīng)歷著生活中突然降臨的一切,毫無防備,就像演員進(jìn)入初排。如果生活中的第一次彩排便是生活本身,那生活有什么價(jià)值呢?(《生命中不能承受之輕》)

               40.他發(fā)現(xiàn)了人類行為的一********自己還不知道——那就是,為了要使一個(gè)大人或小孩極想干某樣事情,只需要設(shè)法把那件事情弄得不易到手就行了。(《湯姆?索亞歷險(xiǎn)記》)

               41.對有信仰的人,死是永生之門。(《失樂園》)

               42.有一個(gè)傳說,說的是有那么一只鳥兒,它一生只唱一次,那歌聲比世上所有一切生靈的歌聲都更加優(yōu)美動(dòng)聽。(《荊棘鳥》)

               43.離開一輩子后,他又回到了自己出生的那片土地上。從小到大,他一直是那個(gè)地方的目擊者。(《尤利西斯》)

               44.同上帝保持聯(lián)系是一碼事,他們都贊同這一點(diǎn),但讓上帝一天二十四小時(shí)都待在身邊就是另一碼事了。(《第二十二條軍規(guī)》)

               45.在甜蜜的夢鄉(xiāng)里,人人都是平等的,但是當(dāng)太陽升起,生存的斗爭重新開始時(shí),人與人之間又是多么的不平等。(《總統(tǒng)先生》)

               46.開發(fā)人類智力的礦藏是少不了要由患難來促成的。(《基度山伯爵》)

               47.離你越近的地方,路途越遠(yuǎn);最簡單的音調(diào),需要最艱苦的練習(xí)。(《泰戈?duì)栐娺x》)

               48.悲傷使人格外敏銳。(《約翰?克里斯朵夫》

               49.我在女人跟前經(jīng)常失敗,就是由于我太愛她們了。(《懺悔錄》)
            posted @ 2007-03-19 20:23 colys| 編輯 收藏

            人妻无码αv中文字幕久久琪琪布 人妻无码久久一区二区三区免费 人妻无码中文久久久久专区 | 91麻豆精品国产91久久久久久| 国产亚洲综合久久系列| 久久九九有精品国产23百花影院| 99精品伊人久久久大香线蕉 | 日日躁夜夜躁狠狠久久AV| 精品久久久久久国产潘金莲 | 97r久久精品国产99国产精| 久久国产亚洲精品麻豆| 综合久久给合久久狠狠狠97色 | 久久中文字幕人妻丝袜| 人妻无码αv中文字幕久久琪琪布| 色综合久久无码中文字幕| 久久久久国产亚洲AV麻豆| 久久丫精品国产亚洲av不卡 | 99久久久精品免费观看国产| 久久只有这精品99| 久久久久久免费一区二区三区| 一本久久a久久精品综合香蕉| 热久久这里只有精品| 亚洲中文字幕无码久久精品1 | 狠狠久久综合| 91视频国产91久久久| 99久久99久久久精品齐齐| 伊人久久大香线蕉综合Av| 国产精品美女久久福利网站| 久久久精品国产亚洲成人满18免费网站| 久久精品国产亚洲AV无码偷窥| 狠狠色丁香久久婷婷综合图片| 久久天天躁狠狠躁夜夜2020| 国产午夜福利精品久久| 四虎国产精品免费久久5151| 99久久无色码中文字幕| 伊人久久久AV老熟妇色| 亚洲人成精品久久久久| 一本色道久久综合狠狠躁| 亚洲欧美成人综合久久久| 亚洲国产精品无码久久久秋霞2| 久久精品一区二区三区AV| 亚洲精品美女久久久久99| 久久久久久久91精品免费观看|