物件導向課程心得Part6

接下來要講到所謂的設計模式
其實到設計模式後面我聽了覺得很硬
加上身體不適腦袋一直空轉
所以有講錯的地方請大力給我鞭下去(我會馬上修正)

在講這個之前先來回想一下前面幾張講到的繼承
其實繼承並非大家眼中看到的這麼美好
繼承也是有缺點在的
缺點
         1、​由於衍生類別必須具有基底類別的所有特性,會增加 衍生類別的約束 
         2、衍生類別會強耦和基底類別,當基底類別被修改也會 影響衍生類別    
舉例
       在父類別多新增一個 virtual方法,那麼子類別就要override這個方法
       所以繼承的關係,最多建議到三層就好,因為繼承的深度越深,要改的地方就會越多
假設
       AB  
       BC
    
   CD
      一旦 C 改變C以前的都要改
      如果是 D改變 D以前的都要改
      所以深度越深,要改的東西就可能越多
SOLID 六大原則
單一職責原則:就一個類別而言,應該僅有一個引起它變化的原因
里式替換原則:軟體使用父類別的地方,一定也會適用於子類別
倚賴倒置原則:高層模組不應倚賴低層模組,兩者都應該倚賴抽象
                         抽象不應該倚賴細節,細節應該倚賴抽象 
介面隔離原則:客戶端不應該倚賴它不需要的介面 ,類別間的倚賴應建立在最小的介面上
開閉原則 : 對擴展開放,對修改封閉 
最少知識原則 (迪米特法則) :一個物件應該對其他物件有最少了解
IoC控制反轉
其實控制反轉在字面上比較難理解
我們把它看成控制權移轉,就是把控制權給別人
不讓自己本身來決定自己要幹嘛
接下來帶大家來看程式碼應該就能很快理解了
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//這是還沒用Ioc的設計方式
namespace IoCSample.NoneIoC
{
    public class Benz
    {
        public void WhoIs()
        {
            Console.WriteLine("I am Benz");
        }
    }

    public class BMW
    {
        public void WhoIs()
        {
            Console.WriteLine("I am BMW");
        }
    }
}


         static void Main(string[] args)
        {
            //非 IOC 呼叫, 上層類別 (Program) 直接倚賴實作, 而且由 Program 決定實做類別
            var car = new NoneIoC.Benz();
            car.WhoIs();
            Console.ReadLine();
        }
這邊很重要,所以一定要注意看清楚我寫的文字

現在問題來了,請問各位,目前決定 var  car 變數內存放什麼東西
是靠誰來決定? 靠等號右邊 new 什麼給他對吧??
所以今天我放 Benz 他就是賓士
如果我要改成BMW怎麼辦????
是不是要進入到  
static void Main(string[] args)
{

}

這個方法內去改? 
改成  var car = new NoneIoC.BMW(); 對吧???
所以你目前依賴的是實體

假設你有20個地方都這樣寫
var car = new NoneIoC.Benz();
客戶今天說 我要改成開Toyota
那你不是要改20次  
 var car = new NoneIoC.BMW() =>  var car = new NoneIoC.Toyota()
這樣你不痛苦嗎???
你保證你都會全部改到,不會漏改?
所以沒有使用Ioc的狀況下
你把控制權放在自己身上,依賴實體,每當需求改變
你就會改到死,說不定還不能準時下班

若我們使用IoC的方式會如何?直接來看Code吧
namespace IoCSample.IoC
{

    //首先建立一個介面
    //讓Benz 跟 BMW 都繼承並且各自實作
    public interface ICar
    {
        void WhoIs();
    }

    internal class Benz : ICar
    {

        public void WhoIs()
        {
            Console.WriteLine("I am Benz");
        }
    }

    internal class BMW : ICar
    {
        public void WhoIs()
        {
            Console.WriteLine("I am BMW");
        }
    }

    //這在邊卡一個工廠,這個工廠來決定 new出來的對向是誰
    //所以這邊我把控制權給了 public class CarFactory
    public class CarFactory
    {
        public static ICar GetCar()
        {
            return new BMW();
        }

    }
}


         static void Main(string[] args)
        {
            var car = IoC.CarFactory.GetCar();//如果你每個地方都這樣寫
            car.WhoIs();                      //客戶如果現在說要開賓士
            Console.ReadLine();               //假設你有20個地方都這樣寫
                                              //20個地方都不用改
                                              //只要改public class CarFactory的GetCar方法
                                              //改成 return new Benz ();
        }

所以現在我們已經把控制權移轉到  public class CarFactory的 GetCar( )
不用再去一個一個改 var car = new NoneIoC.BMW() =>  var car = new NoneIoC.Bezn()
所以我們在設計上多卡這一層
在修改上是不是大大提升速度,也保證不會漏改?