2006年8月11日

          今天在數(shù)值計(jì)算時(shí)碰到一個(gè)問(wèn)題.程序如下:
          ??double a = (3.3-2.4)/0.1;
          ??System.out.println(a);
          你可能認(rèn)為結(jié)果很簡(jiǎn)單,不就是9嘛,是事實(shí)上,結(jié)果為:8.999999998,為什么呢?我翻閱了一些資料,終于找出了原因.
          為什么浮點(diǎn)數(shù)會(huì)丟失精度??
          1. 十進(jìn)制數(shù)的二進(jìn)制表示可能不夠精確

            浮點(diǎn)數(shù)或是雙精度浮點(diǎn)數(shù)無(wú)法精確表示的情況并不少見(jiàn)。浮點(diǎn)數(shù)值沒(méi)辦法用十進(jìn)制來(lái)精確表示的原因要?dú)w咎于CPU表示浮點(diǎn)數(shù)的方法。這樣的話您就可能會(huì)犧牲一些精度,有些浮點(diǎn)數(shù)運(yùn)算也會(huì)引入誤差。以上面提到的情況為例,2.4的二進(jìn)制表示并非就是精確的2.4。反而最為接近的二進(jìn)制表示是 2.3999999999999999。原因在于浮點(diǎn)數(shù)由兩部分組成:指數(shù)和尾數(shù)。浮點(diǎn)數(shù)的值實(shí)際上是由一個(gè)特定的數(shù)學(xué)公式計(jì)算得到的。您所遇到的精度損失會(huì)在任何操作系統(tǒng)和編程環(huán)境中遇到。
            注意: 您可以使用Binary Coded Decimal (BCD)庫(kù)來(lái)保持精度。BCD數(shù)字編碼方法會(huì)把每一個(gè)十進(jìn)制數(shù)字位單獨(dú)編碼。?
          2. 類型失配
            您可能混合了浮點(diǎn)數(shù)和雙精度浮點(diǎn)數(shù)類型。請(qǐng)確定您在進(jìn)行數(shù)學(xué)運(yùn)算的時(shí)候所有的數(shù)據(jù)類型全部相同。
            注意:float類型的變量只有7位的精度,而double類型的變量有15位的精度。

          如何進(jìn)行浮點(diǎn)數(shù)精度計(jì)算?????????????
          ????? Java中的簡(jiǎn)單浮點(diǎn)數(shù)類型float和double不能夠進(jìn)行運(yùn)算。不光是Java,在其它很多編程語(yǔ)言中也有這樣的問(wèn)題。在大多數(shù)情況下,計(jì)算的結(jié)果是準(zhǔn)確的,但是多試幾次(可以做一個(gè)循環(huán))就可以試出類似上面的錯(cuò)誤。現(xiàn)在終于理解為什么要有BCD碼了。
          這個(gè)問(wèn)題相當(dāng)嚴(yán)重,如果你有9.999999999999元,你的計(jì)算機(jī)是不會(huì)認(rèn)為你可以購(gòu)買10元的商品的。
          在有的編程語(yǔ)言中提供了專門的貨幣類型來(lái)處理這種情況,但是Java沒(méi)有。現(xiàn)在讓我們看看如何解決這個(gè)問(wèn)題。
          ?
          四舍五入
          我們的第一個(gè)反應(yīng)是做四舍五入。Math類中的round方法不能設(shè)置保留幾位小數(shù),我們只能象這樣(保留兩位):
          public double round(double value){
          ??? return Math.round(value*100)/100.0;
          }
          非常不幸,上面的代碼并不能正常工作,給這個(gè)方法傳入4.015它將返回4.01而不是4.02,如我們?cè)谏厦婵吹降?br />4.015*100=401.49999999999994
          因此如果我們要做到精確的四舍五入,不能利用簡(jiǎn)單類型做任何運(yùn)算
          java.text.DecimalFormat也不能解決這個(gè)問(wèn)題:
          System.out.println(new java.text.DecimalFormat("0.00").format(4.025));
          輸出是4.02
          ?
          BigDecimal
          在《Effective Java》這本書(shū)中也提到這個(gè)原則,float和double只能用來(lái)做科學(xué)計(jì)算或者是工程計(jì)算,在商業(yè)計(jì)算中我們要用java.math.BigDecimal。BigDecimal一共有4個(gè)夠造方法,我們不關(guān)心用BigInteger來(lái)夠造的那兩個(gè),那么還有兩個(gè),它們是:
          BigDecimal(double val)
          ????????? Translates a double into a BigDecimal.
          BigDecimal(String val)
          ????????? Translates the String repre sentation of a BigDecimal into a BigDecimal.
          上面的API簡(jiǎn)要描述相當(dāng)?shù)拿鞔_,而且通常情況下,上面的那一個(gè)使用起來(lái)要方便一些。我們可能想都不想就用上了,會(huì)有什么問(wèn)題呢?等到出了問(wèn)題的時(shí)候,才發(fā)現(xiàn)上面哪個(gè)夠造方法的詳細(xì)說(shuō)明中有這么一段:
          Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .1000000000000000055511151231257827021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances nonwithstanding.
          The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one.
          原來(lái)我們?nèi)绻枰_計(jì)算,非要用String來(lái)夠造BigDecimal不可!在《Effective Java》一書(shū)中的例子是用String來(lái)夠造BigDecimal的,但是書(shū)上卻沒(méi)有強(qiáng)調(diào)這一點(diǎn),這也許是一個(gè)小小的失誤吧。
          ?
          解決方案
          現(xiàn)在我們已經(jīng)可以解決這個(gè)問(wèn)題了,原則是使用BigDecimal并且一定要用String來(lái)夠造。
          但是想像一下吧,如果我們要做一個(gè)加法運(yùn)算,需要先將兩個(gè)浮點(diǎn)數(shù)轉(zhuǎn)為String,然后夠造成BigDecimal,在其中一個(gè)上調(diào)用add方法,傳入另一個(gè)作為參數(shù),然后把運(yùn)算的結(jié)果(BigDecimal)再轉(zhuǎn)換為浮點(diǎn)數(shù)。你能夠忍受這么煩瑣的過(guò)程嗎?下面我們提供一個(gè)工具類Arith來(lái)簡(jiǎn)化操作。它提供以下靜態(tài)方法,包括加減乘除和四舍五入:
          public static double add(double v1,double v2)
          public static double sub(double v1,double v2)
          public static double mul(double v1,double v2)
          public static double div(double v1,double v2)
          public static double div(double v1,double v2,int scale)
          public static double round(double v,int scale)
          附錄
          源文件Arith.java:
          import java.math.BigDecimal;
          /**
          ?* 由于Java的簡(jiǎn)單類型不能夠精確的對(duì)浮點(diǎn)數(shù)進(jìn)行運(yùn)算,這個(gè)工具類提供精
          ?* 確的浮點(diǎn)數(shù)運(yùn)算,包括加減乘除和四舍五入。
          ?*/
          public class Arith{
          ??? //默認(rèn)除法運(yùn)算精度
          ??? private static final int DEF_DIV_SCALE = 10;
          ??? //這個(gè)類不能實(shí)例化
          ??? private Arith(){
          ??? }
          ?
          ??? /**
          ???? * 提供精確的加法運(yùn)算。
          ???? * @param v1 被加數(shù)
          ???? * @param v2 加數(shù)
          ???? * @return 兩個(gè)參數(shù)的和
          ???? */
          ??? public static double add(double v1,double v2){
          ??????? BigDecimal b1 = new BigDecimal(Double.toString(v1));
          ??????? BigDecimal b2 = new BigDecimal(Double.toString(v2));
          ??????? return b1.add(b2).doubleValue();
          ??? }
          ??? /**
          ???? * 提供精確的減法運(yùn)算。
          ???? * @param v1 被減數(shù)
          ???? * @param v2 減數(shù)
          ???? * @return 兩個(gè)參數(shù)的差
          ???? */
          ??? public static double sub(double v1,double v2){
          ??????? BigDecimal b1 = new BigDecimal(Double.toString(v1));
          ??????? BigDecimal b2 = new BigDecimal(Double.toString(v2));
          ??????? return b1.subtract(b2).doubleValue();
          ??? }
          ??? /**
          ???? * 提供精確的乘法運(yùn)算。
          ???? * @param v1 被乘數(shù)
          ???? * @param v2 乘數(shù)
          ???? * @return 兩個(gè)參數(shù)的積
          ???? */
          ??? public static double mul(double v1,double v2){
          ??????? BigDecimal b1 = new BigDecimal(Double.toString(v1));
          ??????? BigDecimal b2 = new BigDecimal(Double.toString(v2));
          ??????? return b1.multiply(b2).doubleValue();
          ??? }
          ?
          ??? /**
          ???? * 提供(相對(duì))精確的除法運(yùn)算,當(dāng)發(fā)生除不盡的情況時(shí),精確到
          ???? * 小數(shù)點(diǎn)以后10位,以后的數(shù)字四舍五入。
          ???? * @param v1 被除數(shù)
          ???? * @param v2 除數(shù)
          ???? * @return 兩個(gè)參數(shù)的商
          ???? */
          ??? public static double div(double v1,double v2){
          ??????? return div(v1,v2,DEF_DIV_SCALE);
          ??? }
          ?
          ??? /**
          ???? * 提供(相對(duì))精確的除法運(yùn)算。當(dāng)發(fā)生除不盡的情況時(shí),由scale參數(shù)指
          ???? * 定精度,以后的數(shù)字四舍五入。
          ???? * @param v1 被除數(shù)
          ???? * @param v2 除數(shù)
          ???? * @param scale 表示表示需要精確到小數(shù)點(diǎn)以后幾位。
          ???? * @return 兩個(gè)參數(shù)的商
          ???? */
          ??? public static double div(double v1,double v2,int scale){
          ??????? if(scale<0){
          ??????????? throw new IllegalArgumentException(
          ??????????????? "The scale must be a positive integer or zero");
          ??????? }
          ??????? BigDecimal b1 = new BigDecimal(Double.toString(v1));
          ??????? BigDecimal b2 = new BigDecimal(Double.toString(v2));
          ??????? return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
          ??? }
          ?
          ??? /**
          ???? * 提供精確的小數(shù)位四舍五入處理。
          ???? * @param v 需要四舍五入的數(shù)字
          ???? * @param scale 小數(shù)點(diǎn)后保留幾位
          ???? * @return 四舍五入后的結(jié)果
          ???? */
          ??? public static double round(double v,int scale){
          ??????? if(scale<0){
          ??????????? throw new IllegalArgumentException(
          ??????????????? "The scale must be a positive integer or zero");
          ??????? }
          ??????? BigDecimal b = new BigDecimal(Double.toString(v));
          ??????? BigDecimal one = new BigDecimal("1");
          ??????? return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
          ??? }
          };

          posted @ 2006-08-31 11:16 曹青松 閱讀(2945) | 評(píng)論 (4)編輯 收藏

          ??? 可以把普通的 Java 程序做成真正的 exe, 也就是單一個(gè) exe 就可以在沒(méi)有安裝 JVM 的機(jī)器上運(yùn)行。這樣的工具常見(jiàn)的有 JET gcj. 前者是收費(fèi)的,而且做出來(lái)的 exe 還是需要一堆 dll 。推薦使用 gcj. 他有 windows Linux 版,直接下載 zip 包,不需要安裝,里面有不少例子,一些 build 的批處理文件。從原理來(lái)說(shuō) gcj 自己實(shí)現(xiàn)了 JVM 規(guī)范,也就是你編寫(xiě)一個(gè) HelloWorld.java, 其中的 main 方法為 System.out.println("foo");
          當(dāng)使用 gcj 把它做成 exe( 大約 2M ) ,運(yùn)行這個(gè) exe 時(shí),會(huì)啟動(dòng)里面的一個(gè)小型 jvm, 在這上面跑 HelloWorld

          其實(shí),把 Java 做成純 exe 實(shí)在是吃力不討好,有很多限制,文件又大。

          我比較傾向另幾種做法:

          . 使用 InstallAnywhere 等工具,制作一個(gè) exe 的安裝包
          用戶可以選擇使用他機(jī)器上的 JRE 或是這個(gè)安裝包內(nèi)的 JRE 來(lái)運(yùn)行程序
          這是很常見(jiàn)的一種做法,如 JBuilder 就是這么做的。
          這樣的好處是不要求對(duì)方機(jī)器上裝有 JRE ,而且你原來(lái)的程序不需要任何改動(dòng)。
          InstallAnywhere
          中一個(gè)壓縮的 JRE 大概是 8M

          . 制作成可執(zhí)行的 jar, 也就是在 META-INF MANIFEST 文件制定 Main-Class
          可以通過(guò)命令行 java -jar jarfile.jar 來(lái)執(zhí)行, windows 默認(rèn)的把 *.jar 使用 javaw -jar 打開(kāi),所以有些機(jī)器上可以直接雙擊 jar 運(yùn)行。

          . 制作偽 exe, 其實(shí)和上一種做法是一樣的,只不過(guò)做成 exe, 調(diào)用系統(tǒng)的 java.exe 來(lái)運(yùn)行它,這樣的工具有 nativeJ,exe4j


          其實(shí) Java 不像 VB,Delphi 只是一個(gè)語(yǔ)言,而是一個(gè)平臺(tái)。
          jar
          是最常用的部署單元,做成 exe 沒(méi)什么意思。
          一、 exe4j
          ???
          說(shuō)明: exe4j 可以將 Jar 文件制作成 exe 文件,但需 jre 支持,也可將 Jar 文件放在外面。
          ???
          軟件性質(zhì):共享軟件
          ???
          下載地址: http://www.ej-technologies.com/products/exe4j/overview.html
          二、 JBuilder
          ???
          說(shuō)明:新版本的 JBuilder 可以直接把工程制作成各系統(tǒng)的可執(zhí)行文件,包括 Windows 系統(tǒng)。
          ???
          軟件性質(zhì):商業(yè)軟件
          ???
          下載地址:略。我是從 eMule 下載的。
          三、 NativeJ
          ???
          說(shuō)明:與 exe4j 功能類似。
          ???
          軟件性質(zhì):共享軟件
          ???
          下載地址: http://www.dobysoft.com/products/nativej/download.html
          四、 Excelsior JET
          ???
          說(shuō)明:可以直接將 Java 類文件制作成 exe 文件,除 AWT Swing 及第三方圖形接口外可不需 jre 支持( Java5.0 不行)。
          ???
          軟件性質(zhì):共享軟件
          ???
          下載地址: http://excelsior-usa.com/home.html
          五、 jshrink
          ???
          說(shuō)明:可將 Jar 文件打包進(jìn) exe 文件。同時(shí)具有混淆功能(這才是它的主要功能)。
          ???
          軟件性質(zhì):共享軟件
          ???
          下載地址: http://www.e-t.com/jshrink.html
          六、 InstallAnywhere
          ???
          說(shuō)明:打包工具,對(duì) Java 打包最好用。可打包成各操作系統(tǒng)運(yùn)行包。包括 Windows 系統(tǒng)。
          ???
          軟件性質(zhì):商業(yè)軟件。
          ???
          下載地址: http://www.zerog.com/
          七、 InstallShieldX
          ???
          說(shuō)明:與 InstallAnywhere 類似,但比 InstallAnywhere 功能強(qiáng)大。相對(duì)的,比較復(fù)雜,不易上手,我現(xiàn)在還沒(méi)學(xué)會(huì)。
          ???
          軟件性質(zhì):商業(yè)軟件。
          ???
          下載地址: http://www.installshield.com/

          posted @ 2006-08-28 20:37 曹青松 閱讀(1102) | 評(píng)論 (0)編輯 收藏

          Ioc模式

            分離關(guān)注( Separation of Concerns : SOC)是Ioc模式和AOP產(chǎn)生最原始動(dòng)力,通過(guò)功能分解可得到關(guān)注點(diǎn),這些關(guān)注可以是 組件Components, 方面Aspects或服務(wù)Services。

            從GoF設(shè)計(jì)模式中,我們已經(jīng)習(xí)慣一種思維編程方式:Interface Driven Design 接口驅(qū)動(dòng),接口驅(qū)動(dòng)有很多好處,可以提供不同靈活的子類實(shí)現(xiàn),增加代碼穩(wěn)定和健壯性等等,但是接口一定是需要實(shí)現(xiàn)的,也就是如下語(yǔ)句遲早要執(zhí)行:

            AInterface a = new AInterfaceImp();

            AInterfaceImp是接口AInterface的一個(gè)子類,Ioc模式可以延緩接口的實(shí)現(xiàn),根據(jù)需要實(shí)現(xiàn),有個(gè)比喻:接口如同空的模型套,在必要時(shí),需要向模型套注射石膏,這樣才能成為一個(gè)模型實(shí)體,因此,我們將人為控制接口的實(shí)現(xiàn)成為"注射"。

            Ioc英文為 Inversion of Control,即反轉(zhuǎn)模式,這里有著名的好萊塢理論:你呆著別動(dòng),到時(shí)我會(huì)找你。

            其實(shí)Ioc模式也是解決調(diào)用者和被調(diào)用者之間的一種關(guān)系,上述AInterface實(shí)現(xiàn)語(yǔ)句表明當(dāng)前是在調(diào)用被調(diào)用者AInterfaceImp,由于被調(diào)用者名稱寫(xiě)入了調(diào)用者的代碼中,這產(chǎn)生了一個(gè)接口實(shí)現(xiàn)的原罪:彼此聯(lián)系,調(diào)用者和被調(diào)用者有緊密聯(lián)系,在UML中是用依賴 Dependency 表示。

            但是這種依賴在分離關(guān)注的思維下是不可忍耐的,必須切割,實(shí)現(xiàn)調(diào)用者和被調(diào)用者解耦,新的Ioc模式 Dependency Injection 模式由此產(chǎn)生了, Dependency Injection模式是依賴注射的意思,也就是將依賴先剝離,然后在適當(dāng)時(shí)候再注射進(jìn)入。

          Ioc模式(Dependency Injection模式)有三種:

          第一種類型 從JNDI或ServiceManager等獲得被調(diào)用者,這里類似ServiceLocator模式。 1. EJB/J2EE
          2. Avalon(Apache的一個(gè)復(fù)雜使用不多的項(xiàng)目)
          第二種類型 使用JavaBeans的setter方法 1. Spring Framework,
          2. WebWork/XWork
          第三種類型 在構(gòu)造方法中實(shí)現(xiàn)依賴 1. PicoContainer,
          2. HiveMind

            有過(guò)EJB開(kāi)發(fā)經(jīng)驗(yàn)的人都知道,每個(gè)EJB的調(diào)用都需要通過(guò)JNDI尋找到工廠性質(zhì)的Home接口,在我的教程EJB是什么章節(jié)中,我也是從依賴和工廠模式角度來(lái)闡述EJB的使用。

            在通常傳統(tǒng)情況下,為了實(shí)現(xiàn)調(diào)用者和被調(diào)用者解耦,分離,一般是通過(guò)工廠模式實(shí)現(xiàn)的,下面將通過(guò)比較工廠模式和Ioc模式不同,加深理解Ioc模式。

          工廠模式和Ioc
            假設(shè)有兩個(gè)類B 和 C:B作為調(diào)用者,C是被調(diào)用者,在B代碼中存在對(duì)C的調(diào)用:

          public class B{
             private C comp;
            ......
          }
          ?

            實(shí)現(xiàn)comp實(shí)例有兩種途徑:?jiǎn)螒B(tài)工廠模式和Ioc。

          工廠模式實(shí)現(xiàn)如下:

          public class B{
             private C comp;
            private final static MyFactory myFactory = MyFactory.getInstance();

            public B(){
              this.comp = myFactory.createInstanceOfC();

            }
             public void someMethod(){
              this.comp.sayHello();
            }
            ......
          }
          ?

          特點(diǎn):

          每次運(yùn)行時(shí),MyFactory可根據(jù)配置文件XML中定義的C子類實(shí)現(xiàn),通過(guò)createInstanceOfC()生成C的具體實(shí)例。
          使用Ioc依賴性注射( Dependency Injection )實(shí)現(xiàn)Picocontainer如下,B類如同通常POJO類,如下:

          public class B{
             private C comp;
            public B(C comp){
              this.comp = comp;
             }
             public void someMethod(){
              this.comp.sayHello();
             }
            ......
          }
          ?

          假設(shè)C接口/類有有一個(gè)具體實(shí)現(xiàn)CImp類。當(dāng)客戶端調(diào)用B時(shí),使用下列代碼:

          public class client{
             public static void main( String[] args ) {
              DefaultPicoContainer container = new DefaultPicoContainer();
              container.registerComponentImplementation(CImp.class);
              container.registerComponentImplementation(B.class);
              B b = (B) container.getComponentInstance(B.class);
              b.someMethod();
             }
          }
          ?

            因此,當(dāng)客戶端調(diào)用B時(shí),分別使用工廠模式和Ioc有不同的特點(diǎn)和區(qū)別:

            主要區(qū)別體現(xiàn)在B類的代碼,如果使用Ioc,在B類代碼中將不需要嵌入任何工廠模式等的代碼,因?yàn)檫@些工廠模式其實(shí)還是與C有些間接的聯(lián)系,這樣,使用Ioc徹底解耦了B和C之間的聯(lián)系。

            使用Ioc帶來(lái)的代價(jià)是:需要在客戶端或其它某處進(jìn)行B和C之間聯(lián)系的組裝。

            所以,Ioc并沒(méi)有消除B和C之間這樣的聯(lián)系,只是轉(zhuǎn)移了這種聯(lián)系。
            這種聯(lián)系轉(zhuǎn)移實(shí)際也是一種分離關(guān)注,它的影響巨大,它提供了AOP實(shí)現(xiàn)的可能。

          Ioc和AOP
            AOP我們已經(jīng)知道是一種面向切面的編程方式,由于Ioc解放自由了B類,而且可以向B類實(shí)現(xiàn)注射C類具體實(shí)現(xiàn),如果把B類想像成運(yùn)行時(shí)的橫向動(dòng)作,無(wú)疑注入C類子類就是AOP中的一種Advice

            通過(guò)下列代碼說(shuō)明如何使用Picocontainer實(shí)現(xiàn)AOP,該例程主要實(shí)現(xiàn)是記錄logger功能,通過(guò)Picocontainer可以使用簡(jiǎn)單一行,使所有的應(yīng)用類的記錄功能激活。

          首先編制一個(gè)記錄接口:

          public interface Logging {

            public void enableLogging(Log log);

          }
          ?

          有一個(gè)LogSwitcher類,主要用來(lái)激活具體應(yīng)用中的記錄功能:

          import org.apache.commons.logging.Log;
          public class LogSwitcher
          {
            protected Log m_log;
            public void enableLogging(Log log) {
              m_log = log;
              m_log.info("Logging Enabled");
            }
          }

          一般的普通應(yīng)用JavaBeans都可以繼承這個(gè)類,假設(shè)PicoUserManager是一個(gè)用戶管理類,代碼如下:

          public class PicoUserManager extends LogSwitcher
          {
            ..... //用戶管理功能
          }
          public class PicoXXXX1Manager extends LogSwitcher
          {

            ..... //業(yè)務(wù)功能
          }
          public class PicoXXXX2Manager extends LogSwitcher
          {

            ..... //業(yè)務(wù)功能
          }
          ?

          注意LogSwitcher中Log實(shí)例是由外界賦予的,也就是說(shuō)即將被外界注射進(jìn)入,下面看看使用Picocontainer是如何注射Log的具體實(shí)例的。


          DefaultPicoContainer container = new DefaultPicoContainer();
          container.registerComponentImplementation(PicoUserManager.class);
          container.registerComponentImplementation(PicoXXXX1Manager.class);
          container.registerComponentImplementation(PicoXXXX2Manager.class);
          .....

          Logging logging = (Logging) container.getComponentMulticaster();

          logging.enableLogging(new SimpleLog("pico"));//激活log


          ?

            由上代碼可見(jiàn),通過(guò)使用簡(jiǎn)單一行l(wèi)ogging.enableLogging()方法使所有的應(yīng)用類的記錄功能激活。這是不是類似AOP的advice實(shí)現(xiàn)?

            總之,使用Ioc模式,可以不管將來(lái)具體實(shí)現(xiàn),完全在一個(gè)抽象層次進(jìn)行描述和技術(shù)架構(gòu),因此,Ioc模式可以為容器、框架之類的軟件實(shí)現(xiàn)提供了具體的實(shí)現(xiàn)手段,屬于架構(gòu)技術(shù)中一種重要的模式應(yīng)用。

          posted @ 2006-08-11 15:43 曹青松 閱讀(242) | 評(píng)論 (0)編輯 收藏


          posts - 4, comments - 8, trackbacks - 0, articles - 0

          Copyright © 曹青松

          主站蜘蛛池模板: 安泽县| 什邡市| 台东市| 古田县| 郁南县| 准格尔旗| 五莲县| 昆明市| 诸暨市| 武陟县| 独山县| 凤山县| 城市| 长阳| 新竹县| 丰镇市| 五原县| 印江| 乡城县| 威信县| 桐梓县| 绍兴市| 商南县| 玉溪市| 金华市| 米脂县| 南溪县| 沁水县| 稷山县| 开封市| 石景山区| 通江县| 河北省| 会昌县| 和田市| 淳安县| 郧西县| 泸西县| 綦江县| 军事| 利津县|