1.接口
1.1抽象类与接口
image.png1.2抽象类
- 抽象类中可以有实体方法也可以没有
- 一个抽象类继承另外一个抽象类,那么此时,子抽象类可以不用强制重写父抽象类的方法;
abstract class VehicleBase
{
abstract public void Stop();
abstract public void Run();
}
abstract class Vehicle: VehicleBase
{
abstract public void Fill();
}
这类Vehicle继承了VehicleBase,但是没有重写里面的任何一个方法,且自己有重新定义了一个新的抽象方法
-
使用多态实例化的类(隐式声明),不可以调用父类没有的自己的实体方法;如果想调用,需要显示声明
image.png
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
//多态(隐式声明)
Vehicle v = new Car();
v.Run();
Console.ReadKey();
}
}
abstract public class Vehicle
{
public virtual void Run()
{
Console.WriteLine("Vihicle is running....");
}
public void Cargo()
{
Console.WriteLine("Take Cargos");
}
}
public class Car : Vehicle
{
public override void Run()
{
Console.WriteLine("Car is running....");
}
public void Music()
{
Console.WriteLine("play music...");
}
}
}
- 如果一个类,他会继承所有父级抽象类的抽象方法
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
//多态(隐式声明)
Vehicle v = new Car();
v.Run();
Console.ReadKey();
}
}
abstract public class BaseVehichle
{
abstract public void Run();
abstract public void Stop();
}
abstract public class Vehicle:BaseVehichle
{
abstract public void Fill();
public void Cargo()
{
Console.WriteLine("Take Cargos");
}
}
public class Car : Vehicle
{
public override void Fill()
{
throw new NotImplementedException();
}
public void Music()
{
Console.WriteLine("play music...");
}
public override void Run()
{
throw new NotImplementedException();
}
public override void Stop()
{
throw new NotImplementedException();
}
}
}
1.3开放/关闭原则
image.png这种写法违反了开闭原则;改进这种方法,直接使用虚方法
2.接口
2.1抽象类和接口的区别
- 接口的方法必须是public,而抽象方法只要不是private就行
不是用接口
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
var engine = new Engine();
var car = new Car(engine);
car.Run(3);
Console.WriteLine(car.Speed);
Console.ReadKey();
}
}
class Engine
{
public int RPM { get; private set; }
public void Work(int gas)
{
this.RPM = 1000 * gas;
}
}
class Car
{
//耦合Engin类
private Engine _engin;
public Car(Engine engin)
{
_engin = engin;
}
public int Speed { get; private set; }
public void Run(int gas)
{
_engin.Work(gas);
this.Speed = _engin.RPM / 100;
}
}
}
注意:这样写的坏处就是,耦合严重,engine出了问题,很难发现哪里的错误;其次,就是engine出错,写car的程序员就只能等待engine修改好才可以进行工作
2.2使用接口解决紧密耦合
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
var user = new PhoneUser(new NokiaPhone());
user.UserPhone();
Console.ReadKey();
}
}
class PhoneUser
{
private IPhone _phone;
public PhoneUser(IPhone phone )
{
this._phone = phone;
}
public void UserPhone()
{
this._phone.Dail();
this._phone.PickUp();
this._phone.Send();
}
}
interface IPhone
{
void Dail();
void PickUp();
void Send();
}
class NokiaPhone : IPhone
{
public void Dail()
{
Console.WriteLine("Nokia Dailing...");
}
public void PickUp()
{
Console.WriteLine("Nokia Hello...");
}
public void Send()
{
Console.WriteLine("Nokia Sending...");
}
}
class SonyPhone : IPhone
{
public void Dail()
{
Console.WriteLine("Sony Dailing...");
}
public void PickUp()
{
Console.WriteLine("Sony Hello...");
}
public void Send()
{
Console.WriteLine("Sony Sending...");
}
}
}
这样用户可以通过传入的手机类,并调用里面的方法来实现,切换手机直接使用其功能,不用每次都进到类里面修改
2.3接口在单元测试中的应用
image.png依赖关系:电扇依赖电源
如果有一天这个电扇不工作了,不知道是不是电扇坏了,假如为了测试哪里出了问题,调整了电源的电量,那么电源上的其他电器可能会因为调整了电源的电量发生错误,所以我们此时需要改进方法;
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
var fan = new DeskFan(new PowerSupply());
Console.WriteLine(fan.Work());
Console.ReadLine();
}
}
class PowerSupply
{
//固定输出电量100
//当发生错误电量变成300
public int GetPower() { return 300; }
}
class DeskFan
{
private PowerSupply _powerSupply;
public DeskFan(PowerSupply powerSupply)
{
this._powerSupply = powerSupply;
}
public string Work()
{
int power = _powerSupply.GetPower();
if (power<=0)
{
return "won't work";
}
else if (power<100)
{
return "slow";
}
else if (power <200)
{
return "work fine";
}
else
{
return "Broken";
}
}
}
}
- 改进之后,只需要给电风扇传递不同的电源这样子就不需要改正式的电源了
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
var fan = new DeskFan(new PowerSupply());
Console.WriteLine(fan.Work());
Console.ReadLine();
}
}
public interface IPowerSupply
{
int GetPower();
}
public class PowerSupply:IPowerSupply
{
//固定输出电量100
//当发生错误电量变成300
public int GetPower() { return 100; }
}
public class DeskFan
{
private IPowerSupply _powerSupply;
public DeskFan(PowerSupply powerSupply)
{
this._powerSupply = powerSupply;
}
public string Work()
{
int power = _powerSupply.GetPower();
if (power<=0)
{
return "won't work";
}
else if (power<100)
{
return "slow";
}
else if (power <200)
{
return "work fine";
}
else
{
return "Broken";
}
}
}
}
2.4 接口隔离
违反接口隔离原则的设计1
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
var driver1 = new Driver(new Car());
driver1.drive();
Console.ReadKey();
}
}
class Driver
{
private ITank _tank;
private IVehichle _vehicle;
//只可以开车不能开坦克
public Driver(IVehichle vehichle)
{
this._vehicle = vehichle;
}
public void drive()
{
this._vehicle.Run();
}
}
public interface IVehichle
{
void Run();
}
public class Car : IVehichle
{
public void Run()
{
Console.WriteLine("Car is running...");
}
}
public class RaceCar : IVehichle
{
public void Run()
{
Console.WriteLine("RaceCar is running...");
}
}
interface ITank
{
void Fire();
void Run();
}
class LightTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom.....");
}
public void Run()
{
Console.WriteLine("LightTank is running...");
}
}
class MediumTank : ITank
{
public void Fire()
{
Console.WriteLine("Big Boom.....");
}
public void Run()
{
Console.WriteLine("MediumTank is running...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Biggggggggggggggg Boom.....");
}
public void Run()
{
Console.WriteLine("HeavyTank is running...");
}
}
}
这种设计会导致,驾驶员只能开车或者开坦克,其次就是,ITank接口里面,run并非只是Tank独有的,而是是有汽车都应该有的功能;
- 改进:将杂糅的接口分离,使用接口继承来获得接口功能;
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
var driver1 = new Driver(new HeavyTank());
var driver2= new Driver(new RaceCar());
driver1.drive();
driver2.drive();
Console.ReadKey();
}
}
class Driver
{
private IVehichle _vehicle;
//只可以开车不能开坦克
public Driver(IVehichle vehichle)
{
this._vehicle = vehichle;
}
public void drive()
{
this._vehicle.Run();
}
}
interface IWeapon
{
void Fire();
}
public interface IVehichle
{
void Run();
}
public class Car : IVehichle
{
public void Run()
{
Console.WriteLine("Car is running...");
}
}
public class RaceCar : IVehichle
{
public void Run()
{
Console.WriteLine("RaceCar is running...");
}
}
interface ITank:IVehichle,IWeapon
{
void Fire();
void Run();
}
class LightTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom.....");
}
public void Run()
{
Console.WriteLine("LightTank is running...");
}
}
class MediumTank : ITank
{
public void Fire()
{
Console.WriteLine("Big Boom.....");
}
public void Run()
{
Console.WriteLine("MediumTank is running...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Biggggggggggggggg Boom.....");
}
public void Run()
{
Console.WriteLine("HeavyTank is running...");
}
}
}
说明:改进后的代码实现的功能:实例化Driver之后,不管是传Tank还是Car,他都可以实现Run的功能,而由于普通的Driver并不是特殊人员,所以他只拥有driver的能力,这样通过接口实现了功能上的权限问题
接口顯示實現
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
var wk1 = new WarmKiller();//没Kill方法
wk1.Love();
IKiller wk2 = wk1;//显示实现,有Kill,无Love
wk2.Kill();
IKiller wk3 = new WarmKiller();//和上面一样
wk3.Kill();
//如果想调用Love那么,可以使用类型转换
var wk4 = wk3 as IGentleman; //方法一
wk4.Love();
var wk5 = (IGentleman)wk3; //方法一
wk5.Love();
Console.ReadKey();
}
}
interface IKiller
{
void Kill();
}
interface IGentleman
{
void Love();
}
class WarmKiller : IGentleman,IKiller
{
//普通实现
public void Love()
{
Console.WriteLine("loving.....");
}
//显示实现:必须使用IKiller创建实例才会有kill方法
void IKiller.Kill()
{
Console.WriteLine("killing....");
}
}
}
网友评论