<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    The Programming Language Idioms


    Click below to go directly to a specific section:


    重載與重寫 | 靜態(tài)構(gòu)造函數(shù) | 只讀代理 | 同步代理 | 資源管理 | 構(gòu)造函數(shù)中的虛函數(shù)

    ?強(qiáng)制針對接口編程 | 抗變與協(xié)變 | friend interface | ctor vs. setter | 雜項


    重載與重寫

    問題

    日常討論中,術(shù)語的不統(tǒng)一帶來些許混亂

    慣用的表達(dá)

    overload

    重載

    函數(shù)名稱相同,參數(shù)不同(嚴(yán)格的定義還有其它一些限制)

    靜態(tài)決議

    override

    重寫(覆寫,覆蓋,改寫)

    子類重新定義父類定義過的虛函數(shù)(個別語言允許返回值,訪問級別可以不同)

    動態(tài)決議

    示例

    ???? class Base {

    ???? }

    ???? class Derived:Base {

    ???? }

    ???? class Client {

    ???????? void Test(Base obj){

    ????????????? Console.WriteLine("base");

    ???????? }

    ???????? void Test(Derived obj){

    ????????????? Console.WriteLine("derived");

    ???????? }

    ???????? staticvoid Main(string[] args) {

    ????????????? Base obj = new Derived();

    ????????????? new Client().Test(obj);??? //輸出“base”

    ???????? }

    ???? }

    ?


    靜態(tài)構(gòu)造函數(shù)

    問題

    1,在工具類中,通常有一些初始化需要在任何靜態(tài)方法被調(diào)用前進(jìn)行,如配置信息的讀取

    2,普通類中的復(fù)雜的靜態(tài)信息,需要在任何實(shí)例方法被調(diào)用前初始化

    我見過的解決方法

    1,在每個靜態(tài)方法中都調(diào)用必需的初始化步驟

    ???? publicclass SomeUtilClass {

    ???????? private SomeUtilClass(){

    ???????? }

    ???????? privatestaticvoid Init(){

    ????????????? //....

    ???????? }

    ???????? publicstaticstring GetUID(){

    ????????????? Init();

    ????????????? return uid;

    ???????? }

    ????????? publicstaticstring GetConnectionString(){

    ????????????? Init();

    ????????????? return connString;

    ???????? }

    ???? }

    2,在普通構(gòu)造函數(shù)中初始化

    ???? publicclass SomeMapperClass{

    ???????? privatestatic Hashtable types;

    ???????? public SomeMapperClass(){

    ????????????? if(types == null){

    ?????????????????? types = new Hashtable();

    ?????????????????? types.Add("RED", Color.Red);

    ?????????????????? types.Add("GREEN", Color.Green);

    ?????????????????? types.Add("BLUE", Color.Blue);

    ????????????? }

    ???????? }

    ???????? public Color GetColor(string color){

    ????????????? return (Color)types[color];

    ???????? }

    ???? }

    ?

    我推薦的解決方法

    使用靜態(tài)構(gòu)造函數(shù)(C#),或靜態(tài)初始化塊(Java)

    [C#]

    ???? publicclass SomeClass {

    ???????? static SomeClass(){

    ????????????? Init();

    ????????????? types = new Hashtable();

    ????????????? types.Add(...);

    ????????????? types.Add(...);

    ???????? }

    ???? }

    [Java]

    ???? publicclass SomeClass {

    ???????? static{

    ????????????? Init();

    ????????????? types = new HashMap();

    ????????????? types.put("", "");

    ????????????? types.put("", "");

    ???????? }

    ???? }

    效果

    1,Once,only once

    2,定義中對異常處理等有要求,可參考規(guī)范

    2,多線程時是否有問題,我不清楚,討論一下


    只讀代理

    問題

    對象內(nèi)部有一個集合,由這個對象來控制其元素的增加刪除,但客戶需要訪問該集合取得自己想要的信息,而對象不可能為所有的客戶都提供對應(yīng)的方法,因此需要返回內(nèi)部的這個集合,但不允許客戶增加或刪除其元素

    我見過的解決方法

    直接返回代表集合的成員引用,僅在文檔中要求客戶不能增刪集合中的元素

    ???? publicclass SomeClass {

    ???????? private List attrs;

    ???????? public List GetAttributes(){

    ????????????? return attrs;

    ???????? }

    ???? }

    我推薦的解決方法

    1,首選語言提供的功能

    2,次選類庫提供的功能

    3,自己包裝代理類,或返回深度拷貝,或使用AOP

    [C++]

    class config

    {

    public :

    ???? const list & get_attributes(){

    ???????? return attrs;

    ???? }

    private :

    ???? list attrs;

    };

    [C#]

    ???? publicclass SomeClass {

    ???????? private IList attrs;

    ???????? public IList GetAttributes(){

    ????????????? return ArrayList.ReadOnly(attrs);

    ???????? }

    ???? }

    [Java]

    ???? publicclass SomeClass {

    ???????? private List attrs;

    ???????? public List getAttributes(){

    ????????????? return Collections.unmodifiableList(attrs);

    ???????? }

    ???? }

    效果

    1, 語言提供的功能可幫助在編譯期進(jìn)行檢查,確保程序中連試圖增刪元素的代碼都不存在;但對有意無意的const轉(zhuǎn)型無能為力

    2,類庫 提供的功能可幫助在運(yùn)行期進(jìn)行檢查,確保程序中試圖增刪元素的操作都拋出異常


    同步代理

    問題

    為了對象的線程安全引入了同步機(jī)制,卻使對象在單線程環(huán)境下付出了不必要的性能上的代價,曾經(jīng)的例子如寫時拷貝COW

    我見過的解決方法

    就是視而不見,不做任何處理,使用同步原語

    [C#]

    ???? publicclass SomeClass {

    ???????? [MethodImplAttribute(MethodImplOptions.Synchronized)]

    ???????? publicvoid Add(string name){

    ????????????? attrs.Add(name);

    ???????? }

    ???? }

    [Java]

    ???? publicclass SomeClass {

    ???????? publicsynchronizedvoid Add(string name){

    ????????????? attrs.add(name);

    ???????? }

    ???? }

    ?

    我推薦的解決方法

    參考類庫的實(shí)現(xiàn),提供沒有同步的原始類,及有同步的代理類;早期的JDK中Vector及HashTable都是同步的類,新的ArrayList及 HashMap都不是同步的,Collections提供了靜態(tài)方法返回同步代理;當(dāng)在多線程環(huán)境中需要更改集合時,使用代理類

    [C#,多線程環(huán)境中使用同步代理的客戶類代碼]

    ???? publicclass SomeClass {

    ???????? public SomeClass(IList source){

    ????????????? attrs = ArrayList.Synchronized(source);

    ???????? }

    ???????? publicvoid Add(string name){

    ????????????? attrs.Add(name);

    ???????? }

    ???????? publicvoid Remove(string name){

    ????????????? attrs.Remove(name);

    ???????? }

    ???? }

    [C#,單線程環(huán)境中使用同步代理的客戶類代碼]

    ???? publicclass OtherClass{

    ???????? public OtherClass(IList source){

    ????????????? attrs = source;

    ???????? }

    ???????? publicvoid Add(string name){

    ????????????? attrs.Add(name);

    ???????? }

    ???????? publicvoid Remove(string name){

    ????????????? attrs.Remove(name);

    ???????? }

    ???? }

    [Java,多線程環(huán)境中使用同步代理的客戶類代碼]

    ???? publicclass SomeClass {

    ???????? public SomeClass (List source){

    ????????????? attrs = Collections.synchronizedList(source);

    ???????? }

    ???????? publicvoid add(string name){

    ????????????? attrs.add(name);

    ???????? }

    ???? }

    [Java,單線程環(huán)境中使用同步代理的客戶類代碼]

    ???? publicclass OtherClass{

    ???????? public OtherClass(List source){

    ????????????? attrs = source;

    ???????? }

    ???????? publicvoid add(string name){

    ????????????? attrs.add(name);

    ???????? }

    ???? }

    效果

    不必為不需要的功能付出額外的代價


    資源管理

    問題

    有時需要精確的控制資源分配和釋放的時機(jī),保證資源的異常安全,避免資源泄漏,導(dǎo)致死鎖,文件丟失,數(shù)據(jù)庫連接過多等

    我見過的解決方法

    在缺乏真正的局部對象和析構(gòu)函數(shù)的語言中,try/catch/finally充斥在代碼中

    使用中間件可幫助解決部分資源管理,如數(shù)據(jù)庫連接等

    可能會出現(xiàn)基于AOP的資源管理框架

    我推薦的解決方法

    在C++中,自動化的資源管理是與生俱來的,即B.S.提出的“資源管理即初始化”(RAII)

    在C#中,可使用using+IDispose取得近似RAII的效果

    在Java中,我不知道,討論一下

    [C++,RAII,僅僅示例,操作文件應(yīng)首選std::fstream等]

    class File

    {

    public :

    ???? explicit File(string path){

    ???????? pf = fopen(path.c_str(), "rwb");

    ???? }

    ???? ~File(){

    ???????? fclose(pf);

    ???? }

    ???? operator FILE* (){

    ???????? return pf;

    ???? }

    private :

    ???? FILE* pf;

    };

    [C++,RAII的客戶代碼,僅僅示例,操作文件應(yīng)首選std::fstream等]

    void test ()

    {

    ???? File file("auto.txt");

    ???? char buf[256];

    ???? fread(buf, 0, 256, file);// 即使這個操作會拋出異常,文件依然會被關(guān)閉

    }

    [C#,僅僅示例]

    ???? publicclass File:IDisposable {

    ???????? private FileStream fs;

    ???????? public File(string path){

    ????????????? fs = new FileStream(path, FileMode.Create);

    ???????? }

    ???????? publicstaticimplicitoperator FileStream(File file) {

    ????????????? return file.fs;

    ???????? }

    ???????? publicvoid Dispose() {

    ????????????? fs.Close();

    ???????? }

    ???? }

    [C#,僅僅示例]

    ???? publicclass Test{

    ???????? void test(){

    ????????????? using(File file = new File("auto.txt")){

    ?????????????????? //some read, write, etc.

    ????????????? }

    ????????????? // 文件已經(jīng)被關(guān)閉,即使某步操作拋出異常

    ???????? }

    ???? }

    效果

    1,資源管理自動化,不局限于內(nèi)存

    2,C++中使用模板,可統(tǒng)一定義大部分資源的包裝類,目前的C#只能為每種資源定義單獨(dú)的類,或者使用AOP


    構(gòu)造函數(shù)中的虛函數(shù)

    語言特性

    [C++]

    虛函數(shù)與對象狀態(tài)有關(guān),與訪問權(quán)限(public/protected/private)無關(guān)

    只要子類對象構(gòu)造出來了,就可以調(diào)用重寫的方法,不管訪問權(quán)限

    [Java, C#]

    虛函數(shù)與對象狀態(tài)無關(guān),與訪問權(quán)限(public/protected/private/default/internal)有關(guān)

    只要訪問權(quán)限允許,就可以調(diào)用重寫的方法,不管子類對象構(gòu)造出來沒有

    后果

    [C++]

    在基類構(gòu)造函數(shù)/析構(gòu)函數(shù)里調(diào)用的方法永遠(yuǎn)都是基類的實(shí)現(xiàn),不會調(diào)到子類;在其它方法里面虛函數(shù)永遠(yuǎn)都是調(diào)到子類的覆寫實(shí)現(xiàn),不管是不是private

    [Java, C#]

    在基類構(gòu)造函數(shù)里調(diào)用方法,只要子類覆寫了該方法,就會調(diào)到子類的實(shí)現(xiàn)

    解決方法

    慎重的在構(gòu)造函數(shù)中調(diào)用虛函數(shù),尤其是在Java和C#中,至少應(yīng)該在注釋中說明理由


    強(qiáng)制針對接口編程

    問題

    盡管“針對接口編程”做為一條原則已經(jīng)廣為流傳,但實(shí)際應(yīng)用中仍然隨處可見HashMap,Vector等做為接口參數(shù)、返回值傳來傳去

    我見過的解決方法

    使用Factory Method返回接口,并最小化具體類構(gòu)造函數(shù)的訪問權(quán)限,或類本身的訪問權(quán)限

    我推薦的解決方法

    Factory Method依然值得推薦,另外可以利用語言本身的特性來避免多寫一個Factory Method

    在C++中,override一個虛函數(shù)時可以任意改變它的訪問權(quán)限,包括將它由public變?yōu)閜rivate;有人說這樣會破壞封裝,但只要語義正確,有意為之,也沒什么問題

    在C#中,可使用“顯式接口成員實(shí)現(xiàn)”

    在Java中,我不知道,討論一下,或者用Spring吧

    [C++]

    class ISomeInterface

    {

    public :

    ???? virtualvoid SomeMethod() = 0;

    };

    ?

    class SomeClass : public ISomeInterface

    {

    private :

    ???? void SomeMethod(){

    ???????? std::cout << "Subclass\n";

    ???? }

    };

    ?

    int main(int argc, _TCHAR* argv[])

    {

    ???? SomeClass obj;

    ???? obj.SomeMethod();??? //Error

    ???? ISomeInterface& iobj = obj;

    ???? iobj.SomeMethod();?? //Ok

    ???? return 0;

    }

    [C#]

    ???? publicinterface ISomeInterface {

    ???????? void SomeMethod();

    ???? }

    ???? publicclass SomeClass:ISomeInterface {

    ???????? //1 ,不要寫訪問修飾符;2,使用方法全名

    ???????? void ISomeInterface.SomeMethod(){

    ????????????? System.Console.WriteLine("Subclass");

    ???????? }

    }

    ???? publicclass Test{

    ???????? void test(){

    ????????????? SomeClass obj = new SomeClass();

    ????????????? obj.SomeMethod();??? //Error;

    ????????????? ISomeInterface iobj = obj;

    ????????????? iobj.SomeMethod();?? //Ok

    ???????? }

    ???? }

    效果

    1,少寫一個Factory Method

    2,不需要控制構(gòu)造函數(shù)的訪問權(quán)限


    抗變與協(xié)變

    問題

    在override 虛函數(shù)時,子類有時想要返回或處理與父類函數(shù)參數(shù)和返回值略微不同的類型,比如假設(shè)“動物類”有一個“伴侶”的虛函數(shù),其返回值類型為“動物類”,但子類 “兔子”override“伴侶”時,需要把返回值改為“兔子”;假設(shè)“鳥類”有一個“進(jìn)食”的虛函數(shù),其參數(shù)類型為“谷類”,但子類“食鐵鳥” override“進(jìn)食”時,需要把參數(shù)改為“堿性食物”;這時,除了使用泛型可以解決外,就需要用到抗變與協(xié)變

    定義

    抗變:向父類的方向變化
    協(xié)變:向子類的方向變化

    語言支持

    返回值抗變與參數(shù)協(xié)變會帶來明顯的類型安全問題,因此,常用的基本是返回值協(xié)變與參數(shù)抗變;對抗變與協(xié)變支持的最全面的是Eiffel,它同時提供了受束泛型來解決返回值抗變與參數(shù)協(xié)變帶來的類型安全問題

    [C++]

    只支持返回值協(xié)變

    class Animal{

    public :

    ???? virtual Animal const& Spouse() = 0;

    }; 

    class Rabbit : public Animal{

    public :

    ???? Rabbit const& Spouse(){

    ???????? return Rabbit(); //return local reference, don't follow me.

    ???? }

    };

    [C#]

    不支持

    [Java]

    1.5之前不支持,1.5有限度的支持返回值協(xié)變;

    另外迫于checked exception的蹩腳實(shí)現(xiàn),Java支持異常聲明的協(xié)變

    ?

    ?


    friend interface

    問題

    C#和Java取消了friend關(guān)鍵字,增加了“assembly/package”訪問權(quán)限;然而,出于代碼樹合理組織的需要,整個project常常根據(jù)功能模塊被分解成一些小 project,而一些較大的功能模塊,通常包含幾個相互協(xié)作的project,導(dǎo)致了不同的assembly或package;有一些操作,這些相互協(xié)作的assemly或package需要能夠訪問,而不允許其它的assembly或package訪問,如各種setter;但現(xiàn)在的 assembly/package訪問權(quán)限無法做到這一點(diǎn),如果使用public,則所有客戶代碼均可訪問,喪失了安全性

    解決方案

    根據(jù)接口細(xì)分的原則,增加一個friend interface,將部分操作轉(zhuǎn)移到friend interface中,對內(nèi)聚的幾個project/assembly/package,使用friend interface作為接口參數(shù)或返回值,對其它的project/assembly/package則使用安全的接口

    1), 安全接口,供所有客戶使用

    public interface ActivityInstanceSafeInterface {

    ??? /**

    ???? * 獲取分配時間

    ???? */

    ??? Date getAssignTime();?

    ??? /**

    ???? * 獲取提交時間

    ???? */

    ??? Date getCommitTime();?

    ??? /**

    ???? * 獲取激活時間

    ???? */

    ??? Date getActivatedTime();???

    ??? /**

    ???? * 獲取最后一次更新時間

    ???? */

    ??? Date getUpdateTime();???

    }

    2),friend interface,供朋友使用(注意,繼承了安全接口)

    public interface ActivityInstanceFriendInterface extends ActivityInstanceSafeInterface {

    ??? /**

    ???? * 設(shè)置激活時間

    ???? */

    ??? void setActivatedTime(Date date);???

    ??? /**

    ???? * 設(shè)置提交時間

    ???? */

    ??? void setCommitTime(Date date);???

    ??? /**

    ???? * 設(shè)置分配時間

    ???? */?? ?

    ??? void setAssignTime(Date date);???

    ??? /**

    ???? * 設(shè)置最后一次更新時間

    ???? */

    ??? void setUpdateTime(Date date);?

    ??? /**

    ???? * 清除收到的 token

    ???? */

    ??? void clearTokens();

    ??? boolean canStart();

    ??? boolean canFinish();

    }

    3),實(shí)現(xiàn)類,實(shí)現(xiàn)所有接口

    public class ActivityInstance implements ActivityInstanceFriendInterface {

    //……

    }

    ?


    ctor vs. setter

    二者之間的使用場景基本已有定論,這里概述一下

    01#

    決定對象的有效性(或合法性)的資源(即任何業(yè)務(wù)邏輯方法第一次調(diào)用前必須初始化的屬性),應(yīng)該使用ctor獲取

    02#

    對象生命期內(nèi)不變的屬性,應(yīng)該使用ctor獲取

    03#

    實(shí)際應(yīng)用中,推薦盡量使用上述兩條規(guī)則,除非方便性比正確性重要的場合

    ?


    雜項

    問題

    在代碼中發(fā)現(xiàn)了一些書籍中曾經(jīng)提到的小問題,列在這里,提醒一下

    條款

    01#

    請私有化singleton類的構(gòu)造函數(shù)

    02#

    如果不用子類化代替flag,至少使用enum代替接口常量來表示flag

    03#

    訪問控制(public,private等)是針對類型的,不是針對對象的,同一種類型的對象可以任意訪問彼此的私有成員

    ?


    ?

    【推薦參考資料】

    1.C#標(biāo)準(zhǔn):ECMA-334 : C# Language Specification

    2.Java標(biāo)準(zhǔn):The Java? Language Specification Second Edition

    3.C++標(biāo)準(zhǔn):ISO/IEC 14882:2003 Programming Languages - C++

    4.The C# Programming Language

    5.The Java Programming Language

    6.The C++ Programming Language


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     

    posts - 51, comments - 17, trackbacks - 0, articles - 0

    Copyright © 笨蛋啊帆

    主站蜘蛛池模板: 抽搐一进一出gif免费视频| 亚洲国产福利精品一区二区| 国产亚洲精品AAAA片APP| 男女免费观看在线爽爽爽视频| 久久久久久久综合日本亚洲| 男女一进一出抽搐免费视频| 伊人久久大香线蕉亚洲| 福利免费在线观看| 亚洲精品狼友在线播放| 久久国产乱子伦精品免费不卡| 亚洲激情中文字幕| 1000部拍拍拍18勿入免费视频下载 | 亚洲国产一成人久久精品| 大妹子影视剧在线观看全集免费| 亚洲一区无码精品色| 中文字幕无线码中文字幕免费| 亚洲中文字幕无码久久2017| 久草视频在线免费看| 亚洲妓女综合网99| 成人午夜性A级毛片免费| 美女黄色毛片免费看| 黑人大战亚洲人精品一区| 无码av免费网站| 日本亚洲色大成网站www久久| 免费一级毛片在播放视频| 国产免费播放一区二区| 久久亚洲精品人成综合网| 免费精品一区二区三区在线观看| 美女啪啪网站又黄又免费| 亚洲AV无码一区二区三区系列| 91福利免费视频| 精品亚洲国产成人av| 日本亚洲成高清一区二区三区| 麻豆最新国产剧情AV原创免费| 亚洲av日韩综合一区二区三区| 亚洲无av在线中文字幕| 很黄很黄的网站免费的| 日本亚洲中午字幕乱码| 亚洲制服中文字幕第一区| 日本特黄a级高清免费大片| 中文字幕视频免费在线观看|