什么是接口和抽象类
- 接口和抽象类都是“软件工程产物”,软件工业设计的两块基石。
- 具体类->抽象类->接口:越来越抽象,内部实现的东西越来越少
- 抽象类是未完全实现逻辑的类(可以有字段和非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 {
static void Main(string[] args)
{
}
} //具体类concrete abstract class Student //包含抽象方法的类,必须为抽象类 {
abstract public void Study();//抽象类是函数成员没有被完全实现的类
}
/为做基类而生的抽象类与开闭原则/ }
<a name="rtT51"></a>
# 开闭原则
如果不是为了修复Bug或者添加新的功能的话,不要老是修改一个类的代码,特别是类里面函数成员的代码。<br />封装一些不变的,稳定的,固定的和确定的成员,而把那些不确定的,改变的声明为抽象成员,并且留给子类来实现。
<a name="GXpKy"></a>
## Override重写示例
```csharp
namespace Abstract
{
class Program
{
static void Main(string[] args)
{
Vehicle vehicle = new Car();
vehicle.Stop();//如果没有重写方法只能看见Stop
vehicle.Run();//重写查找最新版本的方法(实例)
}
}
class Vehicle
{
public void Stop()
{
Console.WriteLine("Stopped!");
}
public virtual void Run() //重写方法不需要再去判断了
{
Console.WriteLine("Vehicle is running!");//实现没有意义,可以去除方法体变为存虚方法
//存虚方法即为抽象方法,类变为抽象类。
}
}
class Car:Vehicle
{
public override void Run()
{
Console.WriteLine("Car is running");
}
}
class RaceCar:Vehicle
{
public override void Run()
{
Console.WriteLine("Racecar is running");
}
}
/*为做基类而生的抽象类与开闭原则*/
}
用抽象类重构:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Abstract
{
class Program
{
static void Main(string[] args)
{
Vehicle vehicle = new Car();
vehicle.Stop();//如果没有重写方法只能看见Stop
vehicle.Run();//重写查找最新版本的方法(实例)
}
}
abstract class Vehicle
{
public void Stop()
{
Console.WriteLine("Stopped!");
}
public abstract void Run();//virtual删除掉,存虚方法=抽象方法
}
class Car:Vehicle
{
public override void Run()
{
Console.WriteLine("Car is running");
}
}
class RaceCar:Vehicle
{
public override void Run()
{
Console.WriteLine("Racecar is running");
}
}
/*为做基类而生的抽象类与开闭原则*/
}
接口
存抽象类,默认所有成员为abstract public,避免重复。
从抽象类引入抽象类的抽象
namespace Abstract
{
class Program
{
static void Main(string[] args)
{
Vehicle vehicle = new Car();
vehicle.Stop();//如果没有重写方法只能看见Stop
vehicle.Run();//重写查找最新版本的方法(实例)
}
}
abstract class VehicleBase
{
abstract public void Stop();
abstract public void Run();
}
abstract class Vehicle: VehicleBase
{
public override void Stop()
{
Console.WriteLine("Stopped!");
}
}
class Car:Vehicle
{
public override void Run()
{
Console.WriteLine("Car is running");
}
}
class RaceCar:Vehicle
{
public override void Run()
{
Console.WriteLine("Racecar is running");
}
}
/*为做基类而生的抽象类与开闭原则*/
}
抽象类的抽象即是接口
namespace Abstract
{
class Program
{
static void Main(string[] args)
{
Vehicle vehicle = new Car();
vehicle.Stop();//如果没有重写方法只能看见Stop
vehicle.Run();//重写查找最新版本的方法(实例)
}
}
interface IVehicle
{
/*abstract public*/ void Stop();
/*abstract public*/ void Run();
}
abstract class Vehicle: IVehicle
{
public void Stop() //自己实现
{
Console.WriteLine("Stopped!");
}
abstract public void Run();//推给子类去实现
}
class Car:Vehicle
{
public override void Run()
{
Console.WriteLine("Car is running");
}
}
class RaceCar:Vehicle
{
public override void Run()
{
Console.WriteLine("Racecar is running");
}
}
/*为做基类而生的抽象类与开闭原则*/
}
接口与单元测试
- 接口的产生:自底向上(重构),自顶向下(设计)
- 接口的本质:服务的调用者/服务的消费者与服务的提供者之间的契约(contract)
- C#中接口的实现(隐式,显式,多接口)
- 语言对面向对象设计的内建支持:依赖反转,接口隔离,开闭原则……..
从接口方法(完全未实现)—抽象类(未完全实现,abstract)—实现类(override重写)
现实世界中的合作即是程序世界中的依赖。
功能的提供方可替换:
namespace Interface
{
class Program
{
static void Main(string[] args)
{
var phoneUser = new PhoneUser(new Nokia());//只需要改变接口实现的实例
phoneUser.UsePhone();
}
}
interface Iphone
{
void Call();
void PickUp();
void Recive();
void Send();
}
class PhoneUser
{
private Iphone _iphone;
public PhoneUser(Iphone iphone)
{
this._iphone = iphone;
}
public void UsePhone()
{
_iphone.Call();
_iphone.PickUp();
_iphone.Send();
_iphone.Recive();
}
}
class Nokia : Iphone
{
public void Call()
{
Console.WriteLine("Nokia calling");
}
public void PickUp()
{
Console.WriteLine("Hello!This is Tim");
}
public void Recive()
{
Console.WriteLine("Nokia Message");
}
public void Send()
{
Console.WriteLine("Hello");
}
}
class Huawei : Iphone
{
public void Call()
{
Console.WriteLine("Huawei calling");
}
public void PickUp()
{
Console.WriteLine("Hello!This is Tim");
}
public void Recive()
{
Console.WriteLine("Huawei Message");
}
public void Send()
{
Console.WriteLine("Hello");
}
}
}
接口设计
实现:一个抽象类,一个接口实现。
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");
}
}
}
单元测试
电机电扇代码:
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;
}
}
}
测试结果:
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;
}
}
}