天天看點

C#-面向對象程式設計、接口、泛型

面向對象設計原則:

1 開閉原則:對擴充開放,對修改(old Code)關閉

2 類的單一職責:每個類有且隻有一個改變它的原因

3 優先使用組合而非繼承: 避免耦合度過高

4 面向接口程式設計而非面向過程: 定義一個類的時候,先思考對外提供什麼功能,定義一個對外的接口

5 依賴倒置: 依賴抽象代碼,因為具體實作容易改變

6 接口隔離:盡量定義小而精的接口,類實作多個功能,繼承多個接口

7 裡式替換:父類可以被子類替換掉

8 迪米特法則 : 類之間資料傳遞越少越好

C#中抽象類與接口

相同點:

1.可被繼承, 不可被執行個體化,都是抽象的

不同:

1.抽象類可以繼承類或接口 接口隻能繼承接口

2.抽象成員在子類中的實作方式不同,abstract的要用override實作,interface的實作不用

3.抽象類可包含已實作的成員, 接口隻能出現抽象的成員

4.接口可以實作多繼承,抽象類隻能被單繼承,基類必須在接口之前

5.接口中的方法必須被子類實作,抽象類中的方法不用,抽象方法必須被實作

面向對象的三大特性:封裝,繼承,多态

封裝:組織代碼的過程

繼承:對概念和代碼的複用

繼承中的構造函數:構造函數不被繼承,子類建立對象的時候,先調用父類的構造函數,再調用自己的構造函數,在父類沒有無參的構造函數的時候,子類通過Base關鍵字指定調用調用哪個父類的構造函數。

多态:隐藏、重寫、重載

隐藏:在子類中使用new關鍵字實作隐藏父類的方法

重寫:父類方法不适用或者父類的抽象方法,子類中必須重寫。可以重寫的方法:虛方法、重寫方法、抽象方法。

虛方法:用virtual修飾的方法,子類中可以不重寫,抽象類和抽象方法都是用abstract修飾,抽象方法必須出現在抽象類中,子類必須重寫抽象方法。

接口

接口目的為了提高代碼的複用性我們用接口來定義行為

定義一組規範的資料結構,C#中為類提供某些功能

接口不能添加Public外的通路修飾符,接口中所有成員預設Public。接口中不能包含字段和已實作的方法。隻能包含屬性、未實作的方法、事件。

命名規範:一般接口的命名以"I"開頭

實作方式兩種:

隐式實作:通過方法名實作方法,方法前加public

顯示實作(少用):通過“接口.方法名”的形式實作。顯示實作可以避免二義性,通路顯示實作的接口要建立對應接口的類,來進行通路。

namespace 接口
{
    //定義接口: 接口命名以大寫I開頭 , 後面單詞首字母大寫
    //接口可以直接聲明,但是不能被new
    //接口中的成員也是抽象的
    interface IMyInterface
    {
        void Add(int i, int j);
    }
    //接口是抽象的概念,建立接口對象,需要聲明接口new子類
    //接口可以被繼承
    //實作接口的方法不需要 override
    class MyClass : IMyInterface
    {
        public void Add(int a, int b)
        {
            Console.WriteLine(a + b);
        }
    }
    //抽象類,成員可以是非抽象的
    abstract class MyAbstractClass
    {
        public abstract void Add(int i, int j);
        
    }

    class MyClass2 : MyAbstractClass
    {
        public override void Add(int i ,int j)
        {
            Console.WriteLine(i + j);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            IMyInterface myInterface = new MyClass();
            myInterface.Add(2, 2);
        }
    }
}           

複制

顯式實作接口和隐式實作接口

//定義接口: 接口命名以大寫I開頭 , 後面單詞首字母大寫
    //接口可以直接聲明,但是不能被new
    //接口中的成員也是抽象的
    interface IMyInterface
    {
        void Cal(int i, int j);
        string Name { get; set; }
        void Print();
    }
    interface ICal
    {
        void Cal(int i, int j);
    }
    //接口是抽象的概念,建立接口對象,需要聲明接口new子類
    //接口可以被繼承
    //實作接口的方法不需要 override
    
    class MyClass : IMyInterface, ICal
    {
        private string name;
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        //隐式實作接口
        public void Print()
        {
            Console.WriteLine(Name);
        }
        //顯示實作接口
        //想調用顯式接口,需要聲明父接口才可以調用
        void IMyInterface.Cal(int i, int j)
        {
            Console.WriteLine(i + j);
        }
        void ICal.Cal(int i, int j) {
            Console.WriteLine(i - j);
        }

        public void Cal(int a, int b)
        {
            Console.WriteLine(a * b);
        }
    }           

複制

Struct 結構體

我們要複用一些資料時可以使用結構體來直接定義資料的集合

泛型

将類型作為參數,在使用的時候再具體決定

泛型參數可以是多個,一般使用大寫的T開頭

檢討參數一般可以使用在方法 類 委托等

namespace 泛型
{
    class Program
    {
        static void Main(string[] args)
        {
            //泛型 C#2.0 推出的一種新機制 , 簡化 面向對象開發代碼
            //棧
            MyStack<int> myStack = new MyStack<int>();
            myStack.Push(233);
            myStack.Push(1);
            Console.WriteLine(myStack.Pop());
            Console.WriteLine(myStack.Pop());
        }
    }

    class MyStack<T>
    {
        static int cap = 4;
        T[] intStack = new T[cap];
        static int currentIndex = 0;
        public T Pop()
        {
            currentIndex--;
            return intStack[currentIndex];
        }
        public void Push(T i)
        {            
            if(currentIndex >= intStack.Length)
            {
                cap *= 2;
                T[] newStack = new T[cap];
                for(int j = intStack.Length; j < intStack.Length; j++)
                {
                    newStack[j] = intStack[j];
                }
                intStack = newStack;
            }
            intStack[currentIndex] = i;
            currentIndex ++;
        }
    }
}           

複制

第二種寫法

//類型: 不安全的棧 會有拆裝箱操作
    class MyStack2 {
        public void Push<T>(T t) { } 
    }           

複制

進行泛型限制:

限制條件為接口是,将泛型參數類型為接口或者接口的實作類

MyStack2 xixi = new MyStack2();
            xixi.Push<SubCard>(new SubCard());
        }
    }

    class Card
    {

    }
    class SubCard : Card
    {

    }

    //類型: 不安全的棧 會有拆裝箱操作
    class MyStack2 {
        //将T限制為某一類型,或其子類型
        public void Push<T>(T t) where T:Card
        { } 
    }           

複制

使用接口作為泛型限制的執行個體

對任意可比較類型資料進行升序排序(冒泡)

class MyClass02 : IComparable
    {
        public int i;
        public int CompareTo(object obj)
        {
            return i.CompareTo((obj as MyClass02).i);
        }
    }

    //對任意可比較類型資料進行升序排序
    class MyClass01
    {
        public T[] ArraySort<T>(T[] t) where T : IComparable
        {
            if (t.Length > 1)
            {
                for (int n = 0; n < t.Length; n++)
                {
                    for (int m = 0; m < t.Length - n - 1; m++)
                    {
                        //如果前者大于後者
                        if (t[m].CompareTo(t[m + 1]) >= 0)
                        {
                            T temp = t[m + 1];
                            t[m + 1] = t[m];
                            t[m] = temp;
                        }
                    }
                }
            }
            return t;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {         
            MyClass02[] c1 = new MyClass02[3];
            c1[0] = new MyClass02();
            c1[0].i = 11110;
            c1[1] = new MyClass02();
            c1[1].i = 230;
            c1[2] = new MyClass02();
            c1[2].i = 10;

            MyClass01 c3 = new MyClass01();
            c1 = c3.ArraySort<MyClass02>(c1);
            Console.WriteLine(c1[0].i);
            Console.WriteLine(c1[1].i);
            Console.WriteLine(c1[2].i);
        }
    }           

複制

泛型限制

1.引用類型限制

where T:class

引用類型用class表示限制,限制必須為一個類,可以是接口interface

2.值類型限制

where T:struct

int、char類型都是struct

3.構造函數類型限制

where T:new()

指定類型T必須有構造函數

4.轉換類型限制

就是我們可以通過裝箱或者強制類型轉換成目标類型的 類型都可以用于類型參數傳入。