什么是接口和抽象类

  • 接口和抽象类都是“软件工程产物”,软件工业设计的两块基石。
  • 具体类->抽象类->接口:越来越抽象,内部实现的东西越来越少
  • 抽象类是未完全实现逻辑的类(可以有字段和非public成员,他们代表了“具体逻辑”)
  • 抽象类为复用而生:专门作为基类来使用,也具有解耦功能
  • 封装确定的,开放不确定,推迟到合适的子类中去实现
  • 接口是完全为实现逻辑的“类”(“存虚类”;只有函数成员;成员全部public)
  • 接口为解耦而生:“高内聚,低耦合”,方便单元测试
  • 接口是一个“协约”,早已为工业生产所熟知(有分工必有协作,有协作必有协约)
  • 它们都不能实例化,只能用来声明变量、引用具体类(concrete class)的实例

学习设计模式

两个前提(踏踏实实写上两三年代码)

  • 透彻的理解了什么是接口,什么是抽象类,并且能够在实际项目中熟练的使用他们。
  • 熟练理解了SOLID设计原则,并能够在实际项目中自觉的使用。

SOLID设计原则

  • SRP Single Responsibility Principle 单一职责原则
  • OCP Open Closed Principle开闭原则
  • LSP Liskov Substitution Principle里氏替换原则
  • ISP Interface Segregation Principle 接口隔离原则
  • DIP Dependency Inversion Principle 依赖反转原则

抽象类

抽象类的感性认识

  • 包含至少一个抽象方法的类为抽象类
  • 抽象类是至少一个函数成员没有被完全实现的类,未被实现的函数成员不能是private。
  • 不允许实例化抽象类
  • 两个用处:作为基类;声明变量引用子类类型的实例(多态效应)
  • 抽象方法在某些编程语言中也叫存虚方法,虚方法有方法体,抽象方法连方法体都没有 ```csharp namespace Abstract { class Program {

    1. static void Main(string[] args)
    2. {
    3. }

    } //具体类concrete abstract class Student //包含抽象方法的类,必须为抽象类 {

    1. abstract public void Study();//抽象类是函数成员没有被完全实现的类

    }

    /为做基类而生的抽象类与开闭原则/ }

  1. <a name="rtT51"></a>
  2. # 开闭原则
  3. 如果不是为了修复Bug或者添加新的功能的话,不要老是修改一个类的代码,特别是类里面函数成员的代码。<br />封装一些不变的,稳定的,固定的和确定的成员,而把那些不确定的,改变的声明为抽象成员,并且留给子类来实现。
  4. <a name="GXpKy"></a>
  5. ## Override重写示例
  6. ```csharp
  7. namespace Abstract
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. Vehicle vehicle = new Car();
  14. vehicle.Stop();//如果没有重写方法只能看见Stop
  15. vehicle.Run();//重写查找最新版本的方法(实例)
  16. }
  17. }
  18. class Vehicle
  19. {
  20. public void Stop()
  21. {
  22. Console.WriteLine("Stopped!");
  23. }
  24. public virtual void Run() //重写方法不需要再去判断了
  25. {
  26. Console.WriteLine("Vehicle is running!");//实现没有意义,可以去除方法体变为存虚方法
  27. //存虚方法即为抽象方法,类变为抽象类。
  28. }
  29. }
  30. class Car:Vehicle
  31. {
  32. public override void Run()
  33. {
  34. Console.WriteLine("Car is running");
  35. }
  36. }
  37. class RaceCar:Vehicle
  38. {
  39. public override void Run()
  40. {
  41. Console.WriteLine("Racecar is running");
  42. }
  43. }
  44. /*为做基类而生的抽象类与开闭原则*/
  45. }

用抽象类重构:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace Abstract
  7. {
  8. class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. Vehicle vehicle = new Car();
  13. vehicle.Stop();//如果没有重写方法只能看见Stop
  14. vehicle.Run();//重写查找最新版本的方法(实例)
  15. }
  16. }
  17. abstract class Vehicle
  18. {
  19. public void Stop()
  20. {
  21. Console.WriteLine("Stopped!");
  22. }
  23. public abstract void Run();//virtual删除掉,存虚方法=抽象方法
  24. }
  25. class Car:Vehicle
  26. {
  27. public override void Run()
  28. {
  29. Console.WriteLine("Car is running");
  30. }
  31. }
  32. class RaceCar:Vehicle
  33. {
  34. public override void Run()
  35. {
  36. Console.WriteLine("Racecar is running");
  37. }
  38. }
  39. /*为做基类而生的抽象类与开闭原则*/
  40. }

接口

存抽象类,默认所有成员为abstract public,避免重复。

从抽象类引入抽象类的抽象

  1. namespace Abstract
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. Vehicle vehicle = new Car();
  8. vehicle.Stop();//如果没有重写方法只能看见Stop
  9. vehicle.Run();//重写查找最新版本的方法(实例)
  10. }
  11. }
  12. abstract class VehicleBase
  13. {
  14. abstract public void Stop();
  15. abstract public void Run();
  16. }
  17. abstract class Vehicle: VehicleBase
  18. {
  19. public override void Stop()
  20. {
  21. Console.WriteLine("Stopped!");
  22. }
  23. }
  24. class Car:Vehicle
  25. {
  26. public override void Run()
  27. {
  28. Console.WriteLine("Car is running");
  29. }
  30. }
  31. class RaceCar:Vehicle
  32. {
  33. public override void Run()
  34. {
  35. Console.WriteLine("Racecar is running");
  36. }
  37. }
  38. /*为做基类而生的抽象类与开闭原则*/
  39. }

抽象类的抽象即是接口

  1. namespace Abstract
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. Vehicle vehicle = new Car();
  8. vehicle.Stop();//如果没有重写方法只能看见Stop
  9. vehicle.Run();//重写查找最新版本的方法(实例)
  10. }
  11. }
  12. interface IVehicle
  13. {
  14. /*abstract public*/ void Stop();
  15. /*abstract public*/ void Run();
  16. }
  17. abstract class Vehicle: IVehicle
  18. {
  19. public void Stop() //自己实现
  20. {
  21. Console.WriteLine("Stopped!");
  22. }
  23. abstract public void Run();//推给子类去实现
  24. }
  25. class Car:Vehicle
  26. {
  27. public override void Run()
  28. {
  29. Console.WriteLine("Car is running");
  30. }
  31. }
  32. class RaceCar:Vehicle
  33. {
  34. public override void Run()
  35. {
  36. Console.WriteLine("Racecar is running");
  37. }
  38. }
  39. /*为做基类而生的抽象类与开闭原则*/
  40. }

接口与单元测试

  • 接口的产生:自底向上(重构),自顶向下(设计)
  • 接口的本质:服务的调用者/服务的消费者与服务的提供者之间的契约(contract)
  • C#中接口的实现(隐式,显式,多接口)
  • 语言对面向对象设计的内建支持:依赖反转,接口隔离,开闭原则……..

从接口方法(完全未实现)—抽象类(未完全实现,abstract)—实现类(override重写)
image.png
现实世界中的合作即是程序世界中的依赖。
功能的提供方可替换:

  1. namespace Interface
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. var phoneUser = new PhoneUser(new Nokia());//只需要改变接口实现的实例
  8. phoneUser.UsePhone();
  9. }
  10. }
  11. interface Iphone
  12. {
  13. void Call();
  14. void PickUp();
  15. void Recive();
  16. void Send();
  17. }
  18. class PhoneUser
  19. {
  20. private Iphone _iphone;
  21. public PhoneUser(Iphone iphone)
  22. {
  23. this._iphone = iphone;
  24. }
  25. public void UsePhone()
  26. {
  27. _iphone.Call();
  28. _iphone.PickUp();
  29. _iphone.Send();
  30. _iphone.Recive();
  31. }
  32. }
  33. class Nokia : Iphone
  34. {
  35. public void Call()
  36. {
  37. Console.WriteLine("Nokia calling");
  38. }
  39. public void PickUp()
  40. {
  41. Console.WriteLine("Hello!This is Tim");
  42. }
  43. public void Recive()
  44. {
  45. Console.WriteLine("Nokia Message");
  46. }
  47. public void Send()
  48. {
  49. Console.WriteLine("Hello");
  50. }
  51. }
  52. class Huawei : Iphone
  53. {
  54. public void Call()
  55. {
  56. Console.WriteLine("Huawei calling");
  57. }
  58. public void PickUp()
  59. {
  60. Console.WriteLine("Hello!This is Tim");
  61. }
  62. public void Recive()
  63. {
  64. Console.WriteLine("Huawei Message");
  65. }
  66. public void Send()
  67. {
  68. Console.WriteLine("Hello");
  69. }
  70. }
  71. }

接口设计

image.png
实现:一个抽象类,一个接口实现。

namespace InterfaceExampleTwo
{
    class Program
    {
        static void Main(string[] args)
        {
            Driver driver = new CarDriver(new Car());//传入的接口类型 new Car多态,CarDriver也是多态
            driver.personDriver();

            Driver driver1 = new TruckDriver(new Truck());
            driver1.personDriver();
        }
    }

    abstract class Driver
    {
        abstract public void personDriver();     
    }

    class CarDriver : Driver
    {
        private IVehicle _vehicle;
        public CarDriver(IVehicle vehicle)
        {
            _vehicle = vehicle;
        }
        public override void personDriver()
        {
            Console.WriteLine("I'm a CarDriver");
            _vehicle.drive();
        }
    }

    class TruckDriver:Driver
    {
        private IVehicle _vehicle;
        public TruckDriver(IVehicle vehicle)
        {
            _vehicle = vehicle;
        }
        public override void personDriver()
        {
            Console.WriteLine("I'm a TruckDriver");
            _vehicle.drive();
        }
    }

    interface IVehicle
    {
        void drive();
    }

    class Car : IVehicle
    {
        public void drive()
        {
            Console.WriteLine("You drive a car");
        }
    }

    class Truck : IVehicle
    {
        public void drive()
        {
            Console.WriteLine("You drive a truck");
        }
    }
}

实现二:两个接口

namespace InterfaceExampleTwo
{
    class Program
    {
        static void Main(string[] args)
        {
            IDriver driver = new CarDriver(new Car());//传入的接口类型 new Car多态,CarDriver也是多态
            driver.personDriver();

            IDriver driver1 = new TruckDriver(new Truck());
            driver1.personDriver();
        }
    }

    interface IDriver
    {
       void personDriver();     
    }

    class CarDriver : IDriver
    {
        private IVehicle _vehicle;
        public CarDriver(IVehicle vehicle)
        {
            _vehicle = vehicle;
        }
        public void personDriver()
        {
            Console.WriteLine("I'm a CarDriver");
            _vehicle.drive();
        }
    }

    class TruckDriver: IDriver
    {
        private IVehicle _vehicle;
        public TruckDriver(IVehicle vehicle)
        {
            _vehicle = vehicle;
        }
        public void personDriver()
        {
            Console.WriteLine("I'm a TruckDriver");
            _vehicle.drive();
        }
    }

    interface IVehicle
    {
        void drive();
    }

    class Car : IVehicle
    {
        public void drive()
        {
            Console.WriteLine("You drive a car");
        }
    }

    class Truck : IVehicle
    {
        public void drive()
        {
            Console.WriteLine("You drive a truck");
        }
    }
}

单元测试

测试-测试资源管理器
image.png

电机电扇代码:

using System;
namespace InterfaceUnitTest
{
    class Program
    {
        static void Main(string[] args)
        {
            DeskFan deskFan = new DeskFan(new NormalPowerSupply());
            Console.WriteLine(deskFan.Work());
        }
    }

    public interface IPowerSupply
    {
        int GetPower();
    }

    public class NormalPowerSupply:IPowerSupply
    {
        public int GetPower()
        {
            return 140;
        }
    }

    public class DeskFan
    {
        IPowerSupply _powerSupply;
        public DeskFan(IPowerSupply powerSupply)
        {
            this._powerSupply = powerSupply;
        }

        public string Work()
        {
            int power = this._powerSupply.GetPower();
            if (power <= 0)
            {
                return "Won't Work!";
            }
            else if (power < 150)
            {
                return "Work fine";
            }
            else return "Warnning";
        }
    }
}

测试用例:

using System;
using Xunit;

namespace InterfaceUnitTest.Test
{
    public class DeskFanTest
    {
        [Fact]
        public void TestNoPower()
        {
            DeskFan deskFan = new DeskFan(new NoPowerSupply());
            var expected = "Won't Work!";
            var actual = deskFan.Work();
            Assert.Equal(expected, actual);
        }
    }

    class NoPowerSupply : IPowerSupply
    {
        public int GetPower()
        {
            return 0;
        }
    }
}

测试结果:

image.png
InterfaceUnitTest.7z

Mock

Click NuGet Package Manager—Moq

using System;
using Xunit;
using Moq;

namespace InterfaceUnitTest.Test
{
    public class DeskFanTest
    {
        [Fact]
        public void TestNoPower()
        {
            DeskFan deskFan = new DeskFan(new NoPowerSupply());
            var expected = "Won't Work!";
            var actual = deskFan.Work();
            Assert.Equal(expected, actual);
        }

        [Fact] //简化单元测试
        public void TestPowerHigh()
        {
            var mock = new Mock<IPowerSupply>();
            mock.Setup(ps => ps.GetPower()).Returns(() => 220);
            var deskFan = new DeskFan(mock.Object);
            var expected = "Warnning";
            var actual = deskFan.Work();
            Assert.Equal(expected, actual);
        }
    }

    class NoPowerSupply : IPowerSupply
    {
        public int GetPower()
        {
            return 0;
        }
    }
}