目的
- 层可以理解为同类职责的集合,使程序结构更清晰。
实现
-
程序可简单分为三层,分别为
- 表示层(User Interface),简称UI(又称View)。
提供用户界面,如文本框、按钮和提示框等。
响应用户操作,如文本输入,鼠标点击等。- 业务逻辑层(Business Logic Layer),简称BLL或(又称Presenter)。
处理UI层请求,并返回处理结果,即UI单向调用BLL。
依赖注入时,UI单向调用DAL作参数至BLL。
单元测试的重点。- 数据访问层(Data Access Layer),简称DAL(又称Data)。
向BLL层提供持久化数据,即BLL单向调用DAL。
操作数据库,如更新(update)、插入(insert)、删除(delete)和查询(select)等。
操作文件,如读取和写入JSON。- 模型层(Model),三层共用的数据类型。
如接口的定义。
数据类定义,作为参数。
参考代码(实测OK)
- 表示层
using System.Windows.Forms;
using AP = App.Presenters; // 空间别名AP
using AD = App.Data;
namespace App.Views
{
public partial class Login : Form
{
private AP.Login presenter; // 别名.重名类Login,取名简单了
public Login()
{
InitializeComponent();
SetPresenter();
}
private void SetPresenter()
{
// 表示层(UI)单向调用逻辑层(BLL)和数据访问层(DAL)
var user = new AD.User(1);
presenter = new AP.Login(user); // 控制反转(IOC),方便单元测试
}
}
}
- 逻辑层
using App.Models;
using System.Diagnostics;
namespace App.Presenters
{
public class Login
{
private readonly IUser user;
public Login(IUser user)
{
Debug.Assert(user != null);
this.user = user;
}
public bool Validate(string inputPassword)
{
var info = user.GetInfo();
return inputPassword == info.Password;
}
}
}
- 数据层
using App.Models;
using System.Diagnostics;
namespace App.Data
{
public class User : IUser
{
private readonly int userID;
public User(int userID)
{
Debug.Assert(userID > 0); // 检查参数有效性
this.userID = userID;
}
// 实际结果来自数据库,演示采用假定值
public UserInfo GetInfo()
=> new UserInfo
{
Name = "张三",
Password = "1234",
};
}
}
- 模型层
namespace App.Models
{
public class UserInfo
{
public string Name { get; set; }
public string Password { get; set; }
}
}
namespace App.Models
{
public interface IUser
{
UserInfo GetInfo();
}
}
- 单元测试
using App.Models;
using App.Presenters;
using Moq; // 替身工具
using Xunit; // 单元测试工具
namespace AppTests
{
public class LoginTests
{
private Mock<IUser> user = new Mock<IUser>(); // 替身类,免构造器传参
private Login testee; // 被测类
public LoginTests()
{
user.Setup(x => x.GetInfo()).Returns(
new UserInfo
{
Name = "张三",
Password = "1234",
}); // 替身函数
testee = new Login(user.Object);
}
[Theory(DisplayName ="登录检查")]
[InlineData("4321", false)]
[InlineData("1234", true)]
public void Validate_ReturnsTrue(string input, bool expected)
{
bool actual = testee.Validate(input);
Assert.Equal(expected, actual);
}
}
}
资源管理器.jpg
网友评论