一、何为接口?
接口与抽象类类似,仅作为功能声明不作代码实现的语法结构
public interface ICalculator //行业规范接口命名使用一个大写字母I
{
int Calculator();
}
根源上解耦,使系统之间的耦合减到最小
示例代码
Order.cs
public class Order
{
public int Id { get; set; }
public DateTime DatePlaced { get; set; }
public Shipment Shipment { get; set; }
public float TotalPrice { get; set; }
public bool IsShipped { get; set; }
}
OrderProcessor.cs
public class OrderProcessor
{
private readonly IShippingCalculator _shippingCalculator;
public OrderProcessor(IShippingCalculator shippingCalculator)
{
_shippingCalculator = shippingCalculator;
}
public void Process(Order order)
{
if (order.IsShipped)
throw new InvalidOperationException("订单已发货");
order.Shipment = new Shipment
{
Cost = _shippingCalculator.CalculateShipping(order),
ShippingDate = DateTime.Today.AddDays(1)
};
order.IsShipped = true;
Console.WriteLine($"订单#{order.Id}完成,已发货");
}
Program.cs
class Program
{
static void Main(string[] args)
{
var order = new Order
{
Id = 123,
DatePlaced = DateTime.Now,
TotalPrice = 100f
};
IShippingCalculator doubleEleven = new DoubleElevenShippingCalculator();
IShippingCalculator putong = new ShippingCalculator();
var orderProcessor = new OrderProcessor(doubleEleven);
if (DateTime.Now != new DateTime(2024, 11, 11))
{
orderProcessor = new OrderProcessor(putong);
}
Console.Read();
}
}
Shipment.cs
public class Shipment
{
public float Cost { get; set; }
public DateTime ShippingDate { get; set; }
}
ShippingCalculator.cs
class ShippingCalculator : IShippingCalculator
{
public float CalculateShipping(Order order)
{
if (order.TotalPrice < 30f)
return order.TotalPrice * 0.1f;
return 0;
}
}
DoubleElevenShippingCalculator.cs
class DoubleElevenShippingCalculator : IShippingCalculator
{
public float CalculateShipping(Order order)
{
return 0;
}
}
IShippingCalculator.cs
public interface IShippingCalculator
{
public float CalculateShipping(Order order);
}
二、接口与单元测试
添加项目引用后,对OrderProcessor进行测试
[TestClass]
public class OrderProcessorTest
{
//被测方法_条件_期望结果
[TestMethod]
public void Process_OrderUnshipped_SetShippment()
{
OrderProcessor order Processor new OrderProcessor(new FakeShippingCalculator());
Order order = new Order
{
Id = 123,
DatePlaced = DateTime.Now,
TotalPlace = 100f
};
orderProcessor.Process(order);
Assert.AreEqual(order.Shipment.Cost,5);
Assert.IsTrue(order.IsShipped);
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void Process_OrderIsShipped_ThrowException()
{
OrderProcessor orderProcessor = new OrderProcessor(new FakeShippingCalculator());
Order order = new Order
{
Id = 123,
DatePlaced = DateTime.Now,
TotalPlace = 100f,
IsShipped = true
};
orderProcessor.Process(order);
}
}
FakeShippingCalculator.cs
public class FakeShippingCalculator : IShippingCalculator
{
public float ShippingCalculator(Order order)
{
return 5;
}
}
三、反转控制与依赖注入
.NET的一等公民:依赖注入
- [ 依赖关系注入(DI-Dependencies Injection)是一种软件设计模式]
- [ 在类及其依赖项之间实现控制反转(IoC)的技术]
- [ 可以实现类似系统配置、日志记录和选项模式等功能模块的解耦]
IOC与依赖注入
- [ 从不同的角度描述同一件事情 ]
- [ 通过引入IOC容器,实现对象之间的解耦]
- [ 核心思想:面向接口]
IOC的好处
- [ 低耦合性 ]
- [ 标准性]
- [ 可重复性]
查看之前的main代码,可以看到是先通过接口创建价格计算器,再在订单处理器计算方法中绑定价格计算器,因此二者处于高度依赖关系
IShippingCalculator doubleEleven = new DoubleElevenShippingCalculator();
IShippingCalculator putong = new ShippingCalculator();
var orderProcessor = new OrderProcessor(doubleEleven);
故使用依赖注入进行解耦
Program.cs
class Program
{
static void Main(string[] args)
{
var order = new Order
{
Id = 123,
DatePlaced = DateTime.Now,
TotalPrice = 100f
};
//配置IOC
ServiceCollection services = new ServiceCollection();
//singleton,单例模式
//scoped,作用域模式
//tansient,瞬时模式
//services.AddSingleton<IOrderProcessor, OrderProcessor>();
//services.AddTransient<IOrderProcessor, OrderProcessor>();
services.AddScoped<IOrderProcessor, OrderProcessor>();
services.AddScoped<IShippingCalculator, DoubleElevenShippingCalculator>();
//从IOC提取服务
IServiceProvider serviceProvider = services.BuildServiceProvider();
var orderProcessor = serviceProvider.GetService<IOrderProcessor>();
var doubleElevenShippingCalculator = serviceProvider.GetService<IShippingCalculator>();
//处理订单
orderProcessor.Process(order);
float freight= doubleElevenShippingCalculator.CalculateShipping(order);
Console.WriteLine($"运费为{freight}元");
Console.Read();
}
}
IOrderProcessor.cs
public interface IOrderProcessor
{
public void Process(Order order);
}
OrderProcessor.cs
public class OrderProcessor : IOrderProcessor
{
private readonly IShippingCalculator _shippingCalculator;
public OrderProcessor(IShippingCalculator shippingCalculator)
{
Console.WriteLine("OrderProcesor被创建");
_shippingCalculator = shippingCalculator;
}
public void Process(Order order)
{
if (order.IsShipped)
throw new InvalidOperationException("订单已发货");
order.Shipment = new Shipment
{
Cost = _shippingCalculator.CalculateShipping(order),
ShippingDate = DateTime.Today.AddDays(1)
};
order.IsShipped = true;
Console.WriteLine($"订单#{order.Id}完成,已发货");
}
}
DoubleElevenShippingCalculator.cs
class DoubleElevenShippingCalculator : IShippingCalculator
{
public DoubleElevenShippingCalculator()
{
Console.WriteLine("DoubleElevenShippingCalculator被创建");
}
public float CalculateShipping(Order order)
{
return 0;
}
}
四、依赖管理
上述代码使用的是NuGet下的microsoft.extensions.dependencyinjection
五、多重继承?多重实现
C#中不存在多重继承!!!!
我们可以在类中实现多重接口,但这不是多重继承
public class UIText : UIBase, IDragable, ICopyable
{
public void Copy()
{
throw new NotImplementedException();
}
public void Drag()
{
throw new NotImplementedException();
}
public void Paste()
{
throw new NotImplementedException();
}
}
public interface IDragable
{
void Drag();
}
public interface ICopyable
{
void Copy();
void Paste();
}
public class UIBase
{
public int Size { get; set; }
public int Position { get; set; }
public void UIDraw()
{
Console.WriteLine("绘制UI");
}
}
注意区分继承类与接口的区别,对于继承的类来说,可以实现对于方法的重写,然而对于接口来说,只存在对于方法的实现。事实上接口本身的目的就是为了解耦合,而不是代码的复用。
六、接口与多态
OCP开闭原则
Open for extension, and Closed for modification
Open for extension 对于系统的扩展是开放的
Closed for modification 对于修改是关闭的
代码示例
Program.cs
static void Main(string[] args)
{
var order = new Order
{
Id = 123,
DatePlaced = DateTime.Now,
TotalPrice = 30f
};
OrderProcessor orderProcessor = new OrderProcessor();
MailService mailService = new MailService();
orderProcessor.RigisterNotification(mailService);
INotification smsService = new SmsMessageService();
orderProcessor.RigisterNotification(smsService);
orderProcessor.Process(order);
Console.Read();
}
Order.cs
public class Order
{
public int Id { get; set; }
public DateTime DatePlaced { get; set; }
public float TotalPrice { get; set; }
public bool IsShipped { get; set; }
}
OrderProcessor.cs
public class OrderProcessor
{
private readonly List<INotification> messageServices;
public OrderProcessor()
{
messageServices = new List<INotification>();
}
public void RigisterNotification(INotification notification)
{
messageServices.Add(notification);
}
public void Process(Order order)
{
// 处理订单...处理发货...
// 通知用户收货
foreach (INotification notification in messageServices)
{
notification.Send("订单已发货");
}
}
}
MailService.cs
internal class MailService :INotification
{
public void Send(string message)
{
Console.WriteLine("发送EMail"+message);
}
}
INotification.cs
public interface INotification
{
public void Send(string message);
}
SmsMessageService.cs
public class SmsMessageService : INotification
{
public void Send(string message)
{
Console.WriteLine("发送短信:"+message);
}
}