1. 程式人生 > >程式設計師過關斬將--來自於靜態方法和例項方法的聯想翩翩

程式設計師過關斬將--來自於靜態方法和例項方法的聯想翩翩

這兩週沒有妹子來找我問問題,有點小傷感,所以耽誤更新了。哈哈,別當真,因為菜菜這兩週週末都有事(你可以認為去公司加班了),實在是沒有精力,忘各位見諒!!

以下為菜菜自己觀點,不代表任何妹子的觀點,請輕噴

◆◆
面向物件
◆◆

作為一個久經考驗並得到業界肯定的程式設計思想莫過於面向物件程式設計思想了。

面向物件(Object Oriented,OO)是軟體開發方法。面向物件的概念和應用已超越了程式設計和軟體開發,擴充套件到如資料庫系統、互動式介面、應用結構、應用平臺、分散式系統、網路管理結構、CAD技術、人工智慧等領域。面向物件是一種對現實世界理解和抽象的方法,是計算機程式設計技術發展到一定階段後的產物。

談到面向物件思想,首先你得有一個物件才可以。所以計算機天才在語言角度發揮抽象能力,在程式設計中把物件抽象建立了出來,典型的代表作就是java/c# 中的類(class)。把每一個class的型別看做現實世界中的一類物件,然後根據class 可以創建出來多個class的例項,把這些例項看做是面向的具體物件。


為了完美的支援面向物件,大多數語言都支援了特性:封裝,繼承,多型。這也是諸多蛋疼的面試題中的常見題型。


◆◆
應用場景
◆◆

引入例項化方法概念是面向物件概念出現以後的事情了,區分靜態方法和例項化方法不能單單從效能上去理解,建立c++,java,c#這樣面嚮物件語言的大師引入例項化方法一定不是要解決什麼效能、記憶體的問題,而是為了讓開發更加模式化、面向物件化。這樣說的話,靜態方法和例項化方式的區分是為了解決模式的問題。


說的白話一點,到底是使用例項方法還是靜態方法取決於業務的場景,當你的業務中每個物件都有自己的狀態,或者行為,這些狀態和行為是隻屬於當前物件的,那你的行為可以設計成例項方法。

舉一個很簡單的例子:一個遊戲的專案中,每個玩家(player)都有自己的狀態,比如玩家有一個行為:跳躍,不同的玩家跳的距離可能不同,所以這個跳躍的行為體現到程式碼上就是一個player型別例項的方法。


至於靜態方法,一般的定義成型別的行為和狀態。因為型別是所有例項共享的,所以通常用作全域性共享用途。實際專案中會發現有很多的helper類裡邊都是靜態方法,因為這些方法和具體物件,和具體物件的行為狀態沒有任何關係。因為和具體例項沒有連線,所以這型別的靜態方法幾乎都是執行緒安全的。

舉個很簡單的例子:專案中有很多加密的方法,這些方法的作用就是給一個引數,返回一個結果,沒有任何自己的狀態,所以這些方法被設計成靜態方法。


在多數專案中,例項方法的使用量要大於靜態方法,為什麼呢?因為在多數系統中充斥著各種物件的設計,各種XX設計模式的使用,而這些最終都使用了面向物件的思想。舉一個最簡單的mvc例子,無論是java中還是c#的 mvc框架,controller中的方法都是例項方法,因為每個http請求都有自己的狀態,像header頭資訊,body資訊等,這些狀態是屬於當前http請求的,所以這些controller必須是例項方法才行。


幾乎現代所有的流行程式語言都提供了型別例項的繼承和多型,統統都是為了更好的服務面向物件這個理念。為什麼不提供型別的繼承和多型呢?小夥伴們可以留言!

◆◆
常見問題
◆◆

靜態方法是型別的方法,例項方法是每個例項的方法(每個語言形式不太一樣):

class Bird
    {
        //靜態方法
        static bool IsAnimal()
        {
            return true;
        }
        //例項方法
        bool IsCanFly()
        {
            return true;
        }

    }

靜態方法比例項方法快?

菜菜認為這是錯誤的。一個方法的程式碼被載入到記憶體中,然後被cpu去執行,執行的速度快慢和是不是靜態方法沒有任何關係。但是有一個特殊的場景,那就是GC。例項化太多物件在java/c#這類帶有GC的程式語言中會引發垃圾回收操作,當垃圾回收進行的時候會掛起所有的執行緒,所以在這個短暫的時間裡,程式會卡頓。

靜態方法常駐記憶體?

在一個型別第一次被使用的時候,會把靜態方法和靜態變數載入記憶體,直到程序被銷燬。說道常駐記憶體,也算是一種誤解,正確的說法是隻有在被使用之後才會載入進入記憶體。當然在一些語言中可以手動解除安裝當前型別。

靜態方法沒有執行緒安全問題

菜菜認為是錯的。有沒有執行緒安全問題不是是不是靜態所決定的,一個型別也可以有自己的狀態和行為,只不過在一個程序中只有一份而已。當一個型別中的狀態被多個執行緒修改的時候,就會有資源競爭問題,就會有執行緒安全問題。當一個型別的狀態只有讀的情況下,可以認為讀這個方法是執行緒安全的。 自己執行一下以下程式的結果

class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 20; i++)
            {
                Thread t = new Thread(() => {
                    for (int i2 = 0; i2 < 100000; i2++)
                    {
                        Add();
                    }

                });
                t.Start();
            }
            //為了模擬程式一直執行
            while (true)
            {
                Console.WriteLine($"Num的值:"+Num);
                Thread.Sleep(1000);
            }

            Console.Read();
        }

        public static int Num;
        public static void Add()
        {
            Num= Num+1;
        }
    }

至於例項方法的執行緒安全問題,原理類似。有沒有執行緒安全問題取決於狀態有沒有被多個執行緒併發修改,有沒有資源競爭,和是否靜態完全沒關係。

THE END


●程式設計師修神之路--問世間非同步為何物?
●程式設計師修神之路--提高網站的吞吐量