C# - 面向对象 - 接口
面向接口编程 —— 什么是接口
- 接口与抽象类类似,仅作功能声明不做代码实现的语法结构。
- interface关键词,同时接口前固定格式
“I”+“XXX”
为什么需要接口
- 根源上解耦,使系统之间的耦合减到最小,甚至耦合为零。
代码例子
接口代码实现
新建接口
namespace HelloWord
{
public interface IShippingCalculator
{
float CalculateShipping(Order order);
}
}
其他类要使用接口,则需要使用 “:”继承接口
namespace HelloWord
{
internal class DoubleElevenShippingCalculator : IShippingCalculator
{
public float CalculateShipping(Order order)
{
return 0;
}
}
}
实例 (有用到IShippingCalculator的部分)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWord
{
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)
};
Console.WriteLine($"订单#{order.Id}完成,已发货");
}
}
}
using System;
namespace HelloWord
{
class Program
{
static void Main(string[] args)
{
var order = new Order
{
Id = 123,
DatePlaced = DateTime.Now,
TotalPrice = 100f
};
IShippingCalculator doubleElven = new DoubleElevenShippingCalculator();
IShippingCalculator normal = new ShippingCalculator();
var orderProcessor = new OrderProcessor(doubleElven);
if (DateTime.Now != new DateTime(2050, 11, 11)) {
orderProcessor = new OrderProcessor(normal);
}
orderProcessor.Process(order);
Console.Read();
}
}
}
接口与单元测试
新建“MSTest”测试项目
- 注意:“新建项目”该菜单在“解决方案”中,而非项目中。
- 注意:测试项目名称最好遵循的格式:
”项目名称“+”UnitTests“
默认“MSTest”测试项目
global using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace _27interface.UnitTests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
}
}
}
测试前,需要为测试项目添加依赖项
实例
新建FakeShippingCalculator类 —— “假”的价格计算系统
using HelloWord;
namespace _27interface.UnitTests
{
internal class FakeShippingCalculator : IShippingCalculator
{
public float CalculateShipping(Order order)
{
return 5;
}
}
}
测试用例Assert
using HelloWord;
namespace _27interface.UnitTests
{
[TestClass]
public class OrderProcessorTest
{
//被测条件_条件_期望结果
[TestMethod]
public void Process_OrderUnshipped_SetShippment()
{
OrderProcessor orderProcessor = new OrderProcessor(new FakeShippingCalculator());
Order order = new Order
{
Id = 1,
DatePlaced = DateTime.Now,
TotalPrice = 0
};
orderProcessor.Process(order);
//测试用例Assert
Assert.AreEqual(order.Shipment.Cost,5);
Assert.IsTrue(order.IsShipped);
}
[TestMethod]
//指明抛出的异常类型
[ExpectedException(typeof(InvalidOperationException))]
public void Process_OrderUnshipped_ThrowException() {
OrderProcessor orderProcessor = new OrderProcessor(new FakeShippingCalculator());
Order order = new Order
{
Id = 145,
DatePlaced = DateTime.Now,
TotalPrice = 100f,
IsShipped = true
};
orderProcessor.Process(order);
}
}
}
运行测试项目
反转控制与依赖注入
依赖注入
- .NET的一等公民 —— 依赖注入。
- 依赖关系注入(DI- Dependencies Injection)是一种软件设计模式。
- 在类及其依赖项之间实现控制反转(IoC)的技术。
- 可以实现类似系统配置、日志记录和选项模式等功能模块的解耦。
IOC
- Inversion of Control,控制反转、控制倒置。
- 通过独立的接口串联系统。
- IOC容器
IOC容器
依赖注入(DI)
- 获得依赖对象的过程被反转了。
- 控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。
IOC与依赖注入
- 从不同的角度的描述的同一件事情。
- 通过引入IOC容器,实现对象之间的解耦。
- 核心思想∶面向接口。
IOC的好处
实例 —— Nuget项目管理(依赖管理)
在NuGET中安装Microsoft.Extensions.DependencyInjection
配置IOC反转控制容器
using System;
using Microsoft.Extensions.DependencyInjection;
namespace HelloWord
{
class Program
{
static void Main(string[] args)
{
var order = new Order
{
Id = 123,
DatePlaced = DateTime.Now,
TotalPrice = 100f
};
/* IShippingCalculator doubleElven = new DoubleElevenShippingCalculator();
IShippingCalculator normal = new ShippingCalculator();
var orderProcessor = new OrderProcessor(doubleElven);
if (DateTime.Now != new DateTime(2050, 11, 11)) {
orderProcessor = new OrderProcessor(normal);
}
orderProcessor.Process(order);*/
//配置IOC 反转控制容器
ServiceCollection services = new ServiceCollection();
//singleton,单例模式
//scoped,作用域模式
//tansient,瞬时模式
services.AddScoped<IOrderProcessor, OrderProcessor>();
services.AddScoped<IShippingCalculator,DoubleElevenShippingCalculator>();
Console.Read();
}
}
}
singleton,scoped,tansient(从IOC提取服务)(测试)
using System;
using Microsoft.Extensions.DependencyInjection;
namespace HelloWord
{
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 orderProcess = serviceProvider.GetService<IOrderProcessor>();
var orderProcess2 = serviceProvider.GetService<IOrderProcessor>();
Console.Read();
}
}
}
总览
using System;
using Microsoft.Extensions.DependencyInjection;
namespace HelloWord
{
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 orderProcess = serviceProvider.GetService<IOrderProcessor>();
var orderProcess2 = serviceProvider.GetService<IOrderProcessor>();
//处理订单
orderProcess.Process(order);
Console.Read();
}
}
}
多重继承vs多重实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _30Multiple_inheritance_vs.multiple_implementation
{
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 Draw() {
Console.WriteLine("绘制UI");
}
}
internal class Program
{
static void Main(string[] args)
{
Console.Read();
}
}
}
接口与多态
OCP开闭原则
新建接口类 —— INotification.cs
namespace HelloWord
{
public interface INotification
{
public void Send(string message);
}
}
MailService实现INotification
using System;
namespace HelloWord
{
internal class MailService : INotification
{
public void Send(string message)
{
Console.WriteLine("发送email",message);
}
}
}
新建接口类 —— SmsMessageService.cs
using System;
namespace HelloWord
{
public class SmsMessageService : INotification
{
public void Send(string message)
{
Console.WriteLine("短信: " + message);
}
}
}
修改OrderProcessor
using System;
using System.Collections.Generic;
namespace HelloWord
{
public class OrderProcessor
{
/* private readonly MailService _mailService;*/
private readonly List<INotification> messageServices;
public OrderProcessor()
{
messageServices= new List<INotification>();
}
public void RegisterNotification(INotification notification)
{
messageServices.Add(notification);
}
public void Process(Order order)
{
// 处理订单...处理发货...
// 通知用户收货
/*_mailService.Send("订单已发货");*/
foreach (INotification n in messageServices) {
n.Send("订单已发货");
}
}
}
}
Program.cs 新增代码 实现服务
using System;
using System.Collections;
using System.Collections.Generic;
namespace HelloWord
{
class Program
{
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.RegisterNotification(mailService);
INotification smsService = new SmsMessageService();
orderProcessor.RegisterNotification(smsService);
orderProcessor.Process(order);
Console.Read();
}
}
}
面向接口案例改造重构
User.cs
using System;
namespace CMS
{
partial class Program
{
public class User : IUser
{
public bool IsUserLogin { get; set; }
public void Login()
{
string username;
string password;
username = CmdReader("用户名: ");
if (username != "alex")
{
Console.WriteLine("查无此人");
return;
}
password = CmdReader("密码: ");
if (password != "123456")
{
Console.WriteLine("密码错误, 请重试。");
return;
}
IsUserLogin = true;
}
}
}
}
IUser.cs接口
namespace CMS
{
public interface IUser
{
bool IsUserLogin { get; set; }
void Login();
}
}
CMSController
namespace CMS
{
partial class Program
{
public class CMSController : ICMSController
{
private readonly IUser _user;
private readonly IMenu _menu;
public CMSController(IUser user, IMenu menu)
{
_menu = menu;
_user = user;
}
public void Start()
{
// login
do
{
_user.Login();
} while (!_user.IsUserLogin);
// start Menu
_menu.ShowMenu();
}
}
}
}
ICMSController.cs接口
namespace CMS
{
public interface ICMSController
{
void Start();
}
}
Menu.cs
using System;
namespace CMS
{
partial class Program
{
public class Menu : IMenu
{
public void ShowMenu()
{
bool isExit = false;
while (!isExit)
{
string selection = CmdReader("主菜单\n1.客户管理\n2.预约管理\n3.系统设置\n4.退出\n请选择: ");
switch (selection)
{
case "1":
Console.WriteLine("客户管理");
break;
case "2":
Console.WriteLine("预约管理");
break;
case "3":
Console.WriteLine("系统设置");
break;
case "4":
default:
Console.WriteLine("退出");
isExit = true;
break;
}
}
}
}
}
}
IMenu接口
namespace CMS
{
public interface IMenu
{
void ShowMenu();
}
}
Program.cs
创建 IOC 反转控制容器
注册服务
创建BuildServiceProvider,提取cmsController实例
using System;
using Microsoft.Extensions.DependencyInjection;
namespace CMS
{
partial class Program
{
public static string CmdReader(string instruction)
{
Console.Write(instruction);
string cmd = Console.ReadLine();
return cmd;
}
public static void Main(string[] args)
{
// 创建 IOC 反转控制容器
var collection = new ServiceCollection();
// 注册服务
collection.AddScoped<IUser, User>();
collection.AddScoped<IMenu, Menu>();
collection.AddScoped<ICMSController, CMSController>();
// 创建BuildServiceProvider,提取cmsController实例
IServiceProvider serviceProvider = collection.BuildServiceProvider();
var cmsController = serviceProvider.GetService<ICMSController>();
cmsController.Start();
Console.Read();
}
}
}
Comments | NOTHING