# 02 C#面向对象设计 I


**知识结构：**

![图1 知识结构](https://img-blog.csdnimg.cn/20200908093951579.png)

---
## 1、类与对象
- 类：用高级程序语言实现的一个ADT描述。
- 对象：通过类声明的变量。

---
## 2、封装

**2.1 什么是封装**

把类的内部隐藏起来以防止外部看到内部的实现过程。

**2.2 怎样封装**

- 通过限制修饰符`private`、`protected`、`public`、`internal`来实现。
- 对类中的数据（Data）和操作（Operation）的限制修饰符：
    - `private`：只允许类的内部访问（默认）。
    - `protected`：只允许类的内部和子类访问。
    - `public`：类的内部与外部都可以访问。
    - `internal`：在同一程序集内部访问，相当于`public`。
- 对类的限制修饰符：
    - `public`：都可以使用。
    - `internal`：在同一程序集内部使用（默认）。

注：`internal`修饰的类，方法或属性，只要是在同一个程序集中的其它类都可以访问，如果二者不在同一命名空间，只要使用`using`引用上相应的命名空间即可，这里，从另外一个方面也间接看出命名空间并不是界定访问级别的，而是保证全局的类唯一性的。

参考图文：
- [技术图文：如何理解C#的internal限定修饰符？](https://mp.weixin.qq.com/s?__biz=MzIyNDA1NjA1NQ==&mid=2651012035&idx=1&sn=442e2b1e601082b6553ffa06e52c0ae4&chksm=f3e35c5bc494d54d43d9b78947f8e9995208e6404dcd1c92625f780338924261936d227f132d&token=1238973891&lang=zh_CN#rd)

**2.3 怎样表示**

- 类图（Class Diagram）
    - -：`private`
    - +：`public`
    - #：`protected`

![图2 Class Diagram](https://img-blog.csdnimg.cn/2020090718494457.png)

例1：根据下列类图实现Animal类型。


![图3 Class Diagram](https://img-blog.csdnimg.cn/20200907185820336.png)

```c
public class Animal
{
    public int Age;
    public double Weight;
    public void Eat()
    {
        Console.WriteLine("Animal Eat.");
    }
    public void Sleep()
    {
        Console.WriteLine("Animal Sleep.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal al = new Animal();
        al.Eat();// Animal Eat.
        al.Sleep();// Animal Sleep.
    }
}
```

---
## 3、继承

**3.1 什么是继承**

子类拥有父类某些Data和Operation的过程。

**3.2 怎样继承**


```c
public class Child : Parent
{ 
    //… 
}
````
- `Child`：子类（派生类），`Parent`：父类（基类）
- 在类的声明中，利用“:”表示继承。

C# 只支持单继承，但可以定义一个不允许其它类继承的类。
```
public sealed class Name
{
    //...
}
```
- 利用`sealed`关键字可防止所声明的类被继承。


子类与父类中数据与操作的继承关系：
- 父类  `public`  `protected`  `private`   `internal`
- 子类  `public`  `protected`  无法继承  `internal`

**3.3 子类怎样访问父类成员**

利用`base`关键字。

例2：子类访问父类且父类构造函数不带参数。

```c
public class Parent
{
    private int _data1; // 只能被类的内部访问
    protected int Data2; // 能被子类访问和继承
    public int Data3; // 能被子类访问和继承
}

public class Child : Parent
{
    public Child()
    {
        base.Data2 = 2;
        base.Data3 = 3;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Child cld = new Child();
        Console.WriteLine(cld.Data3); // 3
    }
}
```

例3：子类访问父类且父类构造函数带参数。

```c
public class Parent
{
    private int _data1; // 只能被类的内部访问
    protected int Data2; // 能被子类访问和继承
    public int Data3; // 能被子类访问和继承
    public Parent(int dt1, int dt2, int dt3)
    {
        _data1 = dt1;
        Data2 = dt2;
        Data3 = dt3;
    }
}

public class Child : Parent
{
    public Child() : base(0, 2, 3)
    {
        ;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Child cld = new Child();
        Console.WriteLine(cld.Data3);// 3
    }
}
```

**3.4 怎样表示**

- 通过类图来表示


![图4 继承关系](https://img-blog.csdnimg.cn/2020090718590952.png)

例4：根据类图实现程序代码，注意类之间的继承关系。


![图5 Class Diagram](https://img-blog.csdnimg.cn/20200907185946630.png)

```c
public class Animal
{
    public int Age;
    public double Weight;
    public void Eat()
    {
        Console.WriteLine("Animal Eat.");
    }
    public void Sleep()
    {
        Console.WriteLine("Animal Sleep.");
    }
}

public class Bird : Animal
{
    public void Fly()
    {
        Console.WriteLine("Bird Fly.");
    }
}

public class Dog : Animal
{
    public void Run()
    {
        Console.WriteLine("Dog Run.");
    }
}

public class Fish : Animal
{
    public void Swim()
    {
        Console.WriteLine("Fish Swim.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dog dog = new Dog();
        dog.Run(); //Dog Run.
        Bird bird = new Bird();
        bird.Fly(); //Bird Fly.
        Fish fish = new Fish();
        fish.Swim(); //Fish Swim.
    }
}
```

**3.5 实例化**

为对象分配存储空间的过程。

例5：类的实例化。

```c
public class Animal
{
    public int Age;
    public double Weight;
    public void Eat()
    {
        Console.WriteLine("Animal Eat.");
    }
    public void Sleep()
    {
        Console.WriteLine("Animal Sleep.");
    }
}

public class Dog : Animal
{
    public void Run()
    {
        Console.WriteLine("Dog Run.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal al = new Animal(); // 实例化Animal
        al.Eat(); // Animal Eat.
        al.Sleep(); // Animal Sleep.

        Dog dg = new Dog(); // 实例化Dog
        dg.Age = 2;
        dg.Weight = 4.5;
        Console.WriteLine("Dog Infor: Age:{0},Weight:{1}",
            dg.Age, dg.Weight);
        // Dog Infor: Age:2, Weight:4.5
        dg.Sleep(); // Animal Sleep.
        dg.Eat(); // Animal Eat.
        dg.Run(); // Dog Run.
    }
}
```

例6：子类与父类有重名方法。

![图6 Class Diagram](https://img-blog.csdnimg.cn/20200907190525103.png)

```c
public class Animal
{
    public int Age;
    public double Weight;

    public void Eat()
    {
        Console.WriteLine("Animal Eat.");
    }

    public void Sleep()
    {
        Console.WriteLine("Animal Sleep.");
    }
}

public class Dog : Animal
{
    public void Eat()
    {
        Console.WriteLine("Dog Eat.");
    }

    public void Sleep()
    {
        Console.WriteLine("Dog Sleep.");
    }

    public void Run()
    {
        Console.WriteLine("Dog Run.");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Animal al = new Dog(); // 子类可以实例化父类
        al.Eat(); // Animal Eat.（重名方法存在问题）
        al.Sleep(); // Animal Sleep.

        Dog dg = al as Dog; //强制类型转换或Dog dg = (Dog)al;
        dg.Eat(); // Dog Eat.
        dg.Sleep(); // Dog Sleep.
        dg.Run(); // Dog Run.
    }
}
```

注意：

- `Animal al = new Dog();`（正确）
- `Dog dg = new Animal();`（错误）

子类可以实例化父类，而父类不可以实例化子类，即：`Dog`一定是`Animal`，而`Animal`不一定是`Dog`。

- `Animal al = new Dog();`
- `Dog dg = al;`（错误）需要强制类型转换。
- `Dog dg = al as Dog;` （正确）若`al`不是`Dog`类型，返回null。
- `Dog dg = (Dog)al;` （正确）若`al`不是`Dog`类型，系统会抛出异常。




---
## 4、多态

**4.1 什么是多态**

相同的操作（Operation），对于不同的对象，可以有不同的解释，产生不同的执行结果。

**4.2 多态的分类**
- 运行时多态：在运行时决定执行哪个类的哪个方法。（override覆写）
- 编译时多态：在编译时决定执行类中的哪个方法。（overload重载）

**4.3 多态的实现**

运行时多态：

- 在父类中定义并实现虚方法（virtual）
- 在子类中覆写（override）该虚方法。
- 虚方法必须有方法体
- 覆写虚方法，要求方法名，形参，返回值类型必须相同。

例7：实现运行时多态的代码

![图7 Class Diagram](https://img-blog.csdnimg.cn/20200907192621578.png)

```c
public class Animal
{
    public int Age;
    public double Weight;

    public virtual void Eat()
    {
        Console.WriteLine("Animal Eat.");
    }

    public virtual void Sleep()
    {
        Console.WriteLine("Animal Sleep.");
    }
}

public class Dog : Animal
{
    public override void Eat()
    {
        Console.WriteLine("Dog Eat.");
    }

    public override void Sleep()
    {
        Console.WriteLine("Dog Sleep.");
    }

    public virtual void Run()
    {
        Console.WriteLine("Dog Run.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal al = new Dog();
        //在执行时，通过判断al的类型来决定执行哪个类中的哪个方法;
        al.Eat(); // Dog Eat.
        al.Sleep(); // Dog Sleep.
    }
}
```

编译时多态：

- 类中定义的方法或操作符可能有不同的版本。
- 操作符重载：`operator`关键字
- public static 类型 operator 运算符(形参列表){ … }
- 方法重载：必须有相同的方法名、必须有不同的参数列表、可以有相同的返回值类型

例8：通过类图实现编译时多态的代码

![图8 Class Diagram](https://img-blog.csdnimg.cn/2020090808531193.png)

```c
public class Complex
{
    public int A;
    public int B;

    public Complex(int a, int b)
    {
        this.A = a; //this表示在内存中Complex对象
        this.B = b;
    }

    public static Complex operator +(Complex c1, Complex c2)
    {
        return new Complex(c1.A + c2.A, c1.B + c2.B);
    }

    public override string ToString()
    {
        return string.Format("{0}+{1}i", A, B);
    }
}

public class Math
{
    public int Add(int x, int y)
    {
        return x + y;
    }

    public double Add(double x, double y)
    {
        return x + y;
    }

    public Complex Add(Complex x, Complex y)
    {
        return x + y;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Complex c1 = new Complex(1, 2);
        Complex c2 = new Complex(3, 4);
        Complex c3 = c1 + c2;
        Console.WriteLine("C1={0}", c1); // C1=1+2i
        Console.WriteLine("C2={0}", c2); // C2=3+4i
        Console.WriteLine("C3={0}", c3); // C3=4+6i
        Math mth = new Math();
        Complex c4 = mth.Add(c2, c3);
        //在编译时，根据参数列表决定执行哪个类中的哪个方法;
        Console.WriteLine("C4={0}", c4); // C4=7+10i
    }
}
```

总结：`override`和`overload`


![](https://img-blog.csdnimg.cn/2020090809435588.png)



**4.4 抽象方法与抽象类**

- 抽象方法：可以看成没有实现体的虚方法（`abstract`），即只有方法的声明，需要在子类中覆写（`override`）该方法。
- 抽象类：含有抽象方法的类。抽象类不可以直接实例化对象。

例9：根据类图实现代码

![图9 Class Diagram](https://img-blog.csdnimg.cn/2020090809021457.png)

```c
public abstract class Animal
{
    public int Age;
    public double Weight;
    public abstract void Eat();
    public abstract void Sleep();
}

public class Dog : Animal
{
    public override void Eat()
    {
        Console.WriteLine("Dog Eat.");
    }
    public override void Sleep()
    {
        Console.WriteLine("Dog Sleep.");
    }
    public void Run()
    {
        Console.WriteLine("Dog Run.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal al = new Dog();
        al.Eat(); // Dog Eat.
        al.Sleep(); // Dog Sleep.
        ((Dog)al).Run(); // Dog Run.
    }
}
```

注意：
- `al.Run();`（错误）
- `((Dog)al).Run();`（正确）

抽象类中并没有Run方法，如果使用需要强制类型转换。

- `Animal al = new Animal ();`（错误）

抽象类不可以直接实例化对象，系统会抛出异常。

总结：抽象方法和虚方法![](https://img-blog.csdnimg.cn/20200908094431953.png)


例10：饲养系统

某饲养员（Raiser）在目前状态下需要饲养三种动物：狗（Dog）、鸟（Bird）和鱼（Fish），该三种动物只需要让其睡觉（Sleep）和吃饭（Eat）即可。

请设计该饲养系统，要求满足软件设计的“开闭原则”。

方案一：

![图10 Class Diagram](https://img-blog.csdnimg.cn/20200908091105732.png)

```c++
public class Bird
{
    public void Eat()
    {
        Console.WriteLine("Bird Eat.");
    }
    public void Sleep()
    {
        Console.WriteLine("Bird Sleep.");
    }
    public void Fly()
    {
        Console.WriteLine("Bird Fly.");
    }
}

public class Dog
{
    public void Eat()
    {
        Console.WriteLine("Dog Eat.");
    }
    public void Sleep()
    {
        Console.WriteLine("Dog Sleep.");
    }
    public void Run()
    {
        Console.WriteLine("Dog Run.");
    }
}

public class Fish
{
    public void Eat()
    {
        Console.WriteLine("Fish Eat.");
    }
    public void Sleep()
    {
        Console.WriteLine("Fish Sleep.");
    }
    public void Swim()
    {
        Console.WriteLine("Fish Swim.");
    }
}

public class Raiser
{
    public void RaiseDog()
    {
        Dog dog = new Dog();
        dog.Eat();
        dog.Sleep();
    }
    public void RaisBird()
    {
        Bird bird = new Bird();
        bird.Eat();
        bird.Sleep();
    }
    public void RaisFish()
    {
        Fish fish = new Fish();
        fish.Eat();
        fish.Sleep();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Raiser rar = new Raiser();
        rar.RaiseDog();
        // Dog Eat.
        // Dog Sleep.
        rar.RaisBird();
        // Bird Eat.
        // Bird Sleep.
        rar.RaisFish();
        // Fish Eat.
        // Fish Sleep.
    }
}
```

方案二：

![图11 Class Diagram](https://img-blog.csdnimg.cn/20200908092632785.png)

```c
public class Bird
{
    public void Eat()
    {
        Console.WriteLine("Bird Eat.");
    }

    public void Sleep()
    {
        Console.WriteLine("Bird Sleep.");
    }

    public void Fly()
    {
        Console.WriteLine("Bird Fly.");
    }
}

public class Dog
{
    public void Eat()
    {
        Console.WriteLine("Dog Eat.");
    }

    public void Sleep()
    {
        Console.WriteLine("Dog Sleep.");
    }

    public void Run()
    {
        Console.WriteLine("Dog Run.");
    }
}

public class Fish
{
    public void Eat()
    {
        Console.WriteLine("Fish Eat.");
    }

    public void Sleep()
    {
        Console.WriteLine("Fish Sleep.");
    }

    public void Swim()
    {
        Console.WriteLine("Fish Swim.");
    }
}

public enum AnimalType
{
    Dog,
    Bird,
    Fish
};

public class Raiser
{
    public void Raise(AnimalType alt)
    {
        switch (alt)
        {
            case AnimalType.Bird:
                Bird bird = new Bird();
                bird.Eat();
                bird.Sleep();
                break;
            case AnimalType.Dog:
                Dog dog = new Dog();
                dog.Eat();
                dog.Sleep();
                break;
            case AnimalType.Fish:
                Fish fish = new Fish();
                fish.Eat();
                fish.Sleep();
                break;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Raiser rar = new Raiser();
        rar.Raise(AnimalType.Dog);
        // Dog Eat.
        // Dog Sleep.
        rar.Raise(AnimalType.Bird);
        // Bird Eat.
        // Bird Sleep.
        rar.Raise(AnimalType.Fish);
        // Fish Eat.
        // Fish Sleep.
    }
}
```

方案三：

![图12 Class Diagram](https://img-blog.csdnimg.cn/20200908093122441.png)

```c
public abstract class Animal
{
    public int Age;
    public double Weight;
    public abstract void Eat();
    public abstract void Sleep();
}

public class Bird : Animal
{
    public override void Eat()
    {
        Console.WriteLine("Bird Eat.");
    }

    public override void Sleep()
    {
        Console.WriteLine("Bird Sleep.");
    }

    public void Fly()
    {
        Console.WriteLine("Bird Fly.");
    }
}

public class Dog : Animal
{
    public override void Eat()
    {
        Console.WriteLine("Dog Eat.");
    }

    public override void Sleep()
    {
        Console.WriteLine("Dog Sleep.");
    }

    public void Run()
    {
        Console.WriteLine("Dog Run.");
    }
}

public class Fish : Animal
{
    public override void Eat()
    {
        Console.WriteLine("Fish Eat.");
    }

    public override void Sleep()
    {
        Console.WriteLine("Fish Sleep.");
    }

    public void Swim()
    {
        Console.WriteLine("Fish Swim.");
    }
}

public class Raiser
{
    public void Raise(Animal al)
    {
        al.Eat();
        al.Sleep();
    }
}


class Program
{
    static void Main(string[] args)
    {
        Raiser rsr = new Raiser();
        rsr.Raise(new Dog());
        // Dog Eat.
        // Dog Sleep.
        rsr.Raise(new Bird());
        // Bird Eat.
        // Bird Sleep.
        rsr.Raise(new Fish());
        // Fish Eat.
        // Fish Sleep.
    }
}
```

