六边形架构介绍
六边形架构,也被称为洋葱架构(Onion Architecture),是一种遵循整洁架构原则的软件架构模式。它的核心思想是将应用程序分为不同的层,每一层都有明确的职责和依赖关系,以实现可测试、可扩展和可维护的代码结构。
六边形架构的核心概念是领域驱动设计(DDD),它将应用程序划分为三个主要的层:领域层、应用层和基础设施层。每个层都有不同的职责和依赖关系。
1. 领域层(Domain Layer):这是应用程序的核心层,包含业务逻辑和领域模型。它独立于其他层,并不依赖于具体的技术实现。领域层定义了实体、值对象、聚合根、领域服务等概念,并通过领域事件与其他层进行通信。
2. 应用层(Application Layer):这一层是领域层和基础设施层之间的桥梁,负责协调领域层的操作和处理外部请求。它定义了应用程序的用例和操作,将请求转发给领域层进行处理,并将领域层的结果转换为适合外部使用的格式。
3. 基础设施层(Infrastructure Layer):这一层包含了与外部系统的交互、数据访问和其他基础设施相关的代码。它负责与数据库、文件系统、消息队列等进行交互,并提供与外部系统的集成。基础设施层依赖于领域层和应用层,但它们不依赖于具体的技术实现。
六边形架构的关键思想是,内部的层不应该依赖于外部的层,而是通过接口进行通信。这样可以实现层与层之间的解耦,使得应用程序更加灵活和可测试。
六边形架构的原则
六边形架构的优点包括:
可测试性:每个层都可以独立地进行单元测试,因为它们之间的依赖关系通过接口进行定义。
可扩展性:由于各层之间的松耦合,可以方便地添加新的功能或更改现有的实现。
可维护性:由于每个层都有明确的职责,代码结构更加清晰和可读,易于理解和维护。
技术无关性:领域层和应用层不依赖于具体的技术实现,可以方便地更换技术栈而不影响整体架构。
六边形架构的简单示例代码
下面是一个使用C#和.NET实现六边形架构的简单示例代码:
1、领域层
// 领域层
// 定义领域模型
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
// 定义领域服务接口
public interface IUserService
{
User GetUserById(int id);
}
2、应用层
// 应用层
// 实现领域服务接口
public class UserService : IUserService
{
public User GetUserById(int id)
{
// 从数据库或其他数据源获取用户信息
// ...
return new User { Id = id, Name = "John" };
}
}
// 控制器层
// 控制器类
public class UserController : Controller
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
public IActionResult GetUser(int id)
{
// 调用领域服务获取用户信息
User user = _userService.GetUserById(id);
// 返回用户信息
return Ok(user);
}
}
3、基础设施层
// 基础设施层
// 注册依赖关系
public static class DependencyConfig
{
public static void RegisterDependencies(IServiceCollection services)
{
// 注册领域服务
services.AddScoped<IUserService, UserService>();
}
}
// 启动类
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// 注册依赖关系
DependencyConfig.RegisterDependencies(services);
// 添加MVC
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// 使用MVC
app.UseMvc();
}
}
// 程序入口
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
在这个示例中,领域层包含了领域模型(User)和领域服务接口(IUserService)。应用层实现了领域服务接口(UserService),并提供了获取用户信息的功能。控制器层(UserController)依赖于领域服务接口,并通过依赖注入的方式获取领域服务的实例。基础设施层(DependencyConfig)负责注册依赖关系,并将领域服务接口和实现进行绑定。启动类(Startup)配置依赖关系和中间件,并使用MVC来处理请求。最后,程序入口(Program)启动Web服务器。
六边形架构案例加入测试部分
下面是给上面的六边形架构案例加入测试部分的代码示例:
1、领域层(同上)
2、应用层(同上)
3、基础设施层(改变)
// 测试层
// 领域服务测试类
public class UserServiceTests
{
private readonly IUserService _userService;
public UserServiceTests(IUserService userService)
{
_userService = userService;
}
[Fact]
public void GetUserById_ReturnsUser()
{
// Arrange
int userId = 1;
// Act
User user = _userService.GetUserById(userId);
// Assert
Assert.NotNull(user);
Assert.Equal(userId, user.Id);
Assert.Equal("John", user.Name);
}
}
// 基础设施测试类
public class DependencyConfigTests
{
[Fact]
public void RegisterDependencies_RegistersDependencies()
{
// Arrange
IServiceCollection services = new ServiceCollection();
// Act
DependencyConfig.RegisterDependencies(services);
// Assert
Assert.Contains(services, s => s.ServiceType == typeof(IUserService));
}
}
// 控制器测试类
public class UserControllerTests
{
[Fact]
public void GetUser_ReturnsUser()
{
// Arrange
int userId = 1;
var userServiceMock = new Mock<IUserService>();
userServiceMock.Setup(s => s.GetUserById(userId)).Returns(new User { Id = userId, Name = "John" });
var controller = new UserController(userServiceMock.Object);
// Act
var result = controller.GetUser(userId);
// Assert
Assert.IsType<OkObjectResult>(result);
var okResult = (OkObjectResult)result;
Assert.IsType<User>(okResult.Value);
var user = (User)okResult.Value;
Assert.Equal(userId, user.Id);
Assert.Equal("John", user.Name);
}
}
启动类(改变)
// 启动类
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// 注册依赖关系
DependencyConfig.RegisterDependencies(services);
// 添加MVC
services.AddMvc();
// 添加测试服务
services.AddTransient<UserServiceTests>();
services.AddTransient<DependencyConfigTests>();
services.AddTransient<UserControllerTests>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// 使用MVC
app.UseMvc();
// 运行测试
RunTests(app.ApplicationServices);
}
private void RunTests(IServiceProvider serviceProvider)
{
// 获取测试服务
var userServiceTests = serviceProvider.GetService<UserServiceTests>();
var dependencyConfigTests = serviceProvider.GetService<DependencyConfigTests>();
var userControllerTests = serviceProvider.GetService<UserControllerTests>();
// 运行测试
var testOutput = new StringBuilder();
var testResults = new List<ITestResult>();
var testRunner = TestRunnerManager.GetTestRunner();
testResults.AddRange(testRunner.Run(userServiceTests.GetType()));
testResults.AddRange(testRunner.Run(dependencyConfigTests.GetType()));
testResults.AddRange(testRunner.Run(userControllerTests.GetType()));
// 输出测试结果
foreach (var result in testResults)
{
testOutput.AppendLine(#34;{result.Name}: {result.Outcome}");
if (result.Outcome == TestOutcome.Failed)
{
testOutput.AppendLine(result.ErrorMessage);
}
}
// 输出测试结果到控制台
Console.WriteLine(testOutput);
}
}
在这个测试示例中,我们添加了一个测试层,包含了领域服务测试类(UserServiceTests)、基础设施测试类(DependencyConfigTests)和控制器测试类(UserControllerTests)。领域服务测试类和基础设施测试类测试了领域服务和依赖关系的注册。控制器测试类测试了控制器的行为。在启动类的Configure方法中,我们添加了一个RunTests方法,用于运行测试。在这个方法中,我们获取测试服务实例,并使用xUnit测试框架的TestRunnerManager来运行测试。最后,我们将测试结果输出到控制台。
这个示例代码只是一个简单的六边形架构的测试实现,实际应用中可能还涉及到更多的测试场景和组件。但是这个示例可以帮助你理解如何在六边形架构中添加测试,并使用xUnit测试框架来运行测试。
阅读“谈谈六边形架构”的文章后的理解和实践。
文章来源 https://mp.weixin.qq.com/s/nSpj-yV8TFy6qIAG1Vrtag。