天天看點

深入分析面向對象中的對象概念

  OOP:面向對象程式設計,一提到面向對象,大家可能就想到類,接口。一說特性,大家可能張口就來:繼承、封裝、多态,那麼到底什麼樣的對象(類)才是真正意義上的對象呢?特别是現在流行的DDD領域驅動設計思想,講究職責劃分,那麼如何定義一個對象(類)它應該具有的一些特性、行為方法及承擔責任成為關鍵。

  一個看似簡單的問題,其實也是耐人思索,之前也在網上看到一些人關于讨論類的設計問題,認為設計類時不應該考慮資料庫,我覺得這隻是實作真正的面向對象設計的基礎,也是前提條件,大多數程式員之前都是受面向過程程式設計思想的影響,我(夢在旅途)也不例外,一個需要求下來,首先就是想它需要存哪些資料,建哪些表,要定義哪些個方法來完成資料的存儲,整個過程基本是圍繞資料庫來進行的,我這裡稱之為資料驅動程式設計,這樣開發其實也沒有錯,因為存在即有存在的道理,我也可以分析出這種程式設計的優點:開發速度快,執行效率高(沒有層級或層級之前隻是簡單的轉發),缺點是:可讀性差,不利于後續的二次開發等,簡單的應用程式或某個獨立的核心子產品使用這種程式設計方式我覺得也是可以的,但除此之外,我仍覺得合理的面向對象是有必要的,我這裡強調合理,是不要一味的盲目采用某個架構或某種設計模式,沒有最好的架構,同樣也沒有最好的設計模式,唯有最适合的架構與設計模式,那麼如何評估架構與設計是否合适,我認為對象(類)的設計至關重要,下面就我的經驗及我所看到的現象來談談的對象的設計問題,由于我不是什麼大牛,是以難免表達有誤的地方,請多包涵,當然也歡迎大家一起讨論。

1.對象是什麼?

在現實生活中,對象指的是某一個客觀存在的事物,它具有能識别它唯一性的屬性,比如:某人的某個品牌的某個型号的汽車,我這裡為什麼用了多個某個,因為人+品牌+型号+汽車,就能确定具對這個對象,而不是汽車這麼簡單,注意汽車并不是一個對象,它隻是表示的是某類事物,是以通過現實生活的分析,我們可以轉換思想到程式設計的世界中,來分析對象與類的差別。在程式設計中,類就是上面的汽車,而對象則是類的執行個體化,識别對象的唯一性從計算機的角色講,應該是記憶體堆中位址,每一個位址确定一個對象。

2.對象有什麼?

對象指的是具體的某個事物,除了有識别它唯一性的屬性外,它應該還有以下幾個特性:

一、狀态(也可以簡單的稱之為屬性):描述一個對象的特征,這個特征可以永久的,也可以是受外界影響而改變的,比如:某人的某個品牌的某個型号的汽車,如果這輛車重新噴漆,換了一種顔色,那麼的它此時的狀态,顔色被改變;如果車被賣給另外一個人,那麼它此時的狀态,車的所有者也被改變了。

代碼示例:

public class Car //這是一個類
    {
        public Car(string owner,string brand,string model,string color)
        {
            this.Owner = owner;
            this.Brand = brand;
            this.Model = model;
            this.Color = color;
        }

        public string Owner { get; set; }

        public string Brand { get; set; }

        public string Model { get; set; }

        public string Color { get; set; }
    }


        public static void Main(string[] args)
        {
            var car = new Car("張三", "寶馬", "B01", "黑色");//這是一個對象
            car.Color = "紅色";//狀态被改變
            car.Owner = "李四";//狀态被改變
        }      

二、行為(也可以簡單的稱之為方法、函數):一個對象主動或被動去執行某種動作,比如:張三這個人,他吃飯,他看書,他睡覺等都是一種行為,包括我現在寫部落格也是一種行為。行為又分主動與被動,主動是指一個對象主觀意識的動作,比如:張三吃飯就是主動,而被動則是需另一個對象來指令它來執行某種動作,比如:汽車啟動,啟動是一個行為,但它不能自己啟動,需要駕駛人去通過汽車給定的啟動方法與步驟來請求汽車執行啟動,又或者說是取款機,取款機提供一個取款的行為,而具體什麼時候來取,取多少,均由人來告訴它。

public class Car //這是一個類
    {
        public Car(string owner,string brand,string model,string color)
        {
            this.Owner = owner;
            this.Brand = brand;
            this.Model = model;
            this.Color = color;
        }

        public string Owner { get; set; }

        public string Brand { get; set; }

        public string Model { get; set; }

        public string Color { get; set; }

        public string Status { get; private set; }


        public Driver Driver { get; set; }

        public void Start() //啟動方法,被動
        {
            if (this.Driver!=null)
            {
                this.Status = "運作中";
            }
            else
            {
                throw new InvalidOperationException("沒有駕駛員,不能自動啟動!");
            }
        }

        public void Stop() //啟動方法,被動
        {
            this.Status = "停止";
        }
    }


    public class Driver
    {
        public string Name { get; set; }

        public Driver(string name)
        {
            this.Name = name;
        }

        public void  Drive(Car car)//駕駛,主動
        {
            car.Driver = this; //坐在車上
            car.Start();//啟動汽車,并運作
            car.Stop();//到達終點,停止汽車
        }
    }

    public class APP9
    {
        public static void Main(string[] args)
        {
            var car = new Car("張三", "寶馬", "B01", "黑色");//這是一個對象
            var driver = new Driver("李四");
            driver.Drive(car);//李四來開張三的車,現實生活中不能随便借車開哦!~V~
        }
    }
      

有人看了上面的代碼後,可能再想,不是所有的對象都有行為吧,既然是行為,行為又代表一種動作,那麼也隻有能動的對象才有行為,不能動的對象就沒有,是這樣嗎?我在寫這篇博文前也思考了這個問題,開始也這樣認為的,後面仔細一想,不對,應該是所有的對象都有行為,就拿不動的東西來說吧,比如一張紙,紙本身本是不能動的,但如果你把它扔起來,那麼紙就具備了被動的移動方法,根據愛因斯坦的相對論,沒有絕對的靜止,隻有相對的靜止,是以就看在什麼情況下,參照物是什麼,有點扯遠了哈,回歸正題,有人可能還是不服,所有的對象都有行為方法,那我不是非要對所有的類都定義方法嗎,不然就不符合真正的對象?我認為不是這樣的,場景決定一個對象的狀态與方法,這也是下面我将要說明的角色定位的問題,這裡我可以很負責任的告訴你,我們所有的定義的對象都有行為,隻是你沒有意識到而矣,是什麼呢?那就是構造函數與析構函數,它們就是被動的行為方法,這也是符合現實生活的對象,任何一個對象都有建立與毀滅,你敢說不是嗎?請舉出例子來吧!

3.對象角色定位

任何一個對象在不同的場景中應該有不同的狀态及行為,比如:張三,張三在學校他是學生,具有學生的狀态及行為,在公司工作他是員工,具有員工的狀态及行為,取得駕照駕駛汽車,具備駕駛員的狀态及行為,在圖書館看書,具備讀者的狀态與行為。由此可知,對象是複雜的,類是具體一些,對象存在多變性,而類則應具備不變性,可能有人不明白,我這裡具體解釋一下,我這裡說的可變性,不是面向對象的那個多态,而是指對象角色的可變性,比如:學生類,那麼它就表示學生,它不可能還表示作者,當然它可以表示人,但一般人不會這樣表示,而對象則不同,正如上面我講的張三的不同角色,他不同類的執行個體化,類不支援多重繼承,我覺得對的,因為一個類可以代表一個角色,一個角色隻能做這個角色的事情,比如:學生,他就是學習,老師,他就是教書,有人可能還會說,兼職多個角色,又是員工又是駕駛員,又是老師同時又是學生,是的,确實存在,但上面說過了,兼職的時候一個對象不可能同時做某個事情,比如:又是員工又是駕駛員,難道他同時工作又同時開車,有人說:計程車司機呀!好吧,你曆害,但仍然是角色不同,計程車司機開車就是工作,當他不工作開車時,他就是駕駛員。好了,說了這麼多,看是來看一下代碼示例吧!

public class Person //人
    {
        public string IdNo{get;set;}

        public string Name { get; set; }

        public string Sex { get; set; }

        public double Height { get; set; }

        public double Weight { get; set; }

        public DateTime BirthDay { get; set; }

    }

    public class Post //文章
    {

        public string Title { get; set; }

        public string Content { get; set; }

        public Author Author { get; set; }
        
        public DateTime CreateDatetime { get; set; }

    }

    public class Author : Person //角色為作者
    {
        public void Write(Post post)
        {
            //行為
        }
    }


    public class Book //書
    {
        public string Name { get; set; }

        public DateTime IssuedDate { get; set; }

        public List<Post> Posts;

    }

    public class Library //圖書館
    {
        public string Name { get; set; }

        public List<Book> Books { get; set; }

        public void Borrow(Reader reader, IEnumerable<Book> books) //借出書,被動
        {
            Books.RemoveAll(b=>books.Contains(b));
            //其它操作
        }

        public void Return(Reader reader,IEnumerable<Book> books)//還入書,被動
        {
            Books.AddRange(books);
            //其它操作
        }
    }

    public class Reader : Person //角色為讀者
    {
        public List<Book> Books { get; set; }

        public IEnumerable<Post> Read(Book book,params int[] pages) //讀書,主動
        {
            var posts = new List<Post>();
            if (pages != null)
            {
                foreach(int i in pages)
                {
                    posts.Add(book.Posts[i]);
                }
            }
            else
            {
                posts = book.Posts;
            }
            return posts;
        }

        public void Borrow(IEnumerable<Book> books, Library library) //主動借書
        {
            library.Borrow(this,books);
            Books.AddRange(books);
        }

        public void Return(IEnumerable<Book> books, Library library)//主動還書
        {
            library.Return(this, books);
            Books.RemoveAll(b => books.Contains(b));
        }

    }

    public class Driver:Person //角色為駕駛員
    {
        public void Drive(Car car)
        {
            car.Driver = this;
            car.Start();
            car.Stop();
        }
    }

    public class Car
    {
        public Driver Driver { get; set; }

        public string Status{get;private set;}

        public void Start()
        {
            this.Status="運作中";
        }

        public void Stop()
        {
            this.Status="停止";
        }
    }
      

結 尾

我這裡隻是定義,沒有列出運作時代碼。例子比較簡單,大家看一下就好了。最後要說明的是,對象雖然都有狀态與行為,而且角色不同狀态與行為也随之不同,但在程式設計的世界裡,我們可以隻關注我們所關注的,比如:一個部落格系統,我們隻關注作者,閱讀者,回複者三個角色,從這三個角色應該具備的狀态與行為進行設計相關的類,這樣就比較符合真實的對象了,也就不會出現大家常見的:狀态類-僵屍類(隻有屬性,無方法),方法類-孤魂野鬼類(隻有方法,無屬性)

好了,文章到這裡就結束了,面向對象的思想博大精深,很難一下子全部說明白,但相信隻要我們在程式設計中多思考多總結就能提升我們程式設計覺悟,有朝一日成為大師。在此向大師、大牛們緻敬,向你們學習,學習的道路永遠止境。這篇文章我花了一上午的時間,想了很多,寫得卻不是很多,但都是源自我的想法,如果幫助到大家了,還請支援推薦一下哦,非常感謝!

繼續閱讀