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 myStack = new MyStack();
            myStack.Push(233);
            myStack.Push(1);
            Console.WriteLine(myStack.Pop());
            Console.WriteLine(myStack.Pop());
        }
    }

    class MyStack
    {
        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) { } 
    }

进行泛型约束:
约束条件为接口是,将泛型参数类型为接口或者接口的实现类

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

    class Card
    {

    }
    class SubCard : Card
    {

    }

    //类型: 不安全的栈 会有拆装箱操作
    class MyStack2 {
        //将T约束为某一类型,或其子类型
        public void Push(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) 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(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.转换类型约束

就是我们可以通过装箱或者强制类型转换成目标类型的 类型都可以用于类型参数传入。

你可能感兴趣的:(C#-面向对象编程、接口、泛型)