1

我可以提供一些关于“关注点分离”的指导。我正在开发一个假期预订应用程序,以尝试提高我的 DI 和 TDD 知识,我有两个独立的存储库“Allocation”和“PublicHoliday”,它们都有自己的业务逻辑类 AllocationLogic 和 PublicHolidayLogic。

AllocationLogic 有一个名为CalculateWorkingDays 的方法,该方法计算用户必须为给定范围(分配对象的开始日期和结束日期属性)分配假期的日期。

PublicHolidayLogic 有一个名为 PublicHolidaysForTheYear 的方法,它可以获取一年中的所有银行假日。而不是将此方法中的代码复制到CalculateWorkingDays 方法中,我想从CalculateworkingDays 方法中的PublicHolidayLogic 类中调用它。

我的问题是可以在 CalculateworkingDays 方法中创建 publicHolidayLogic 类的实例,通过 Allocation 构造函数传入所需的存储库吗?或者我应该在分配构造函数中将接口传递给 publicholidaylogic。

我希望前者,但我附上了我的代码,任何帮助将不胜感激

-- 公共假期班

 public class PublicHolidayLogic : IPublicHolidayLogic
{
    private IPublicHolidayRepository _publicHolidayRepository;

    public PublicHolidayLogic(IPublicHolidayRepository publicHolidayRepo)
    {
        _publicHolidayRepository = publicHolidayRepo;
    }


    public System.Collections.Generic.IEnumerable<Domain.Models.PublicHoliday> 
        PublicHolidaysForTheYear(int year, int countryId)
    {
        var returnedDates = _publicHolidayRepository.Enumerable()
            .Where(t => t.StartDate.Year == year && t.CountryId == countryId).ToList();

        List<Domain.Models.PublicHoliday> _result = new List<Domain.Models.PublicHoliday>();

        foreach(Domain.Models.PublicHoliday p in returnedDates)
        {
            if (!_result.Any(t => t.Name == p.Name && t.StartDate == p.StartDate))
              _result.Add(p);
        }

        return _result.AsEnumerable();
    }
}

-- 分配类

 public class AllocationLogic : IAllocationLogic
{
    private IAllocationRepository _allocationRepository;
    private IPublicHolidayRepository _publicHolidayRepository;

    public AllocationLogic(IAllocationRepository allocationRepo, 
                           IPublicHolidayRepository publicHolidayRepository)
    {
        _allocationRepository = allocationRepo;
        _publicHolidayRepository = publicHolidayRepository;
    }

    public int CalculateWorkingDays(Domain.Models.Allocation allocation)
    {
        //TODO A Better way of doing this would be nice.
        List<DateTime> _dates = new List<DateTime>();
        List<DateTime> _result = new List<DateTime>();

        //Monday To Friday Only

        for (DateTime i = allocation.StartDate; i <= allocation.EndDate; i = i.AddDays(1))
        {
            if (i.DayOfWeek != DayOfWeek.Saturday 
                && i.DayOfWeek != DayOfWeek.Sunday 
                && !_dates.Contains(i))

                _dates.Add(i);
        }

        //Remove Bank Holidays
        if (_publicHolidayRepository != null)
        {
            IEnumerable<Domain.Models.PublicHoliday> _holidays 
                = new PublicHolidayLogic(_publicHolidayRepository)
                    .PublicHolidaysForTheYear(allocation.StartDate.Year, allocation.User.CountryId);

            if (_holidays.Count() > 0)
            {
                foreach (DateTime d in _dates)
                {
                    if (!_holidays.Any(t => t.StartDate == d))
                    {
                        _result.Add(d);
                    }
                }
            }
            else
            {
                _result.AddRange(_dates);
            }
        }
        else
        {
            _result.AddRange(_dates);
        }
        return _result.Count;

    }
}

-- 分配测试类

[TestClass]
public class AllocationLogicTests
{

    [TestMethod]
    public void CalculateWorkingDaysOnly()
    {
        //Holiday
        var allocation = new Allocation { 
            StartDate = new DateTime(2013, 1, 7), 
            EndDate = new DateTime(2013, 1, 18) 
        };
        var user = new User { CountryId = 1 };

        var allocationLogic = new AllocationLogic(null,null);

        allocation.User = user;
        int result = allocationLogic.CalculateWorkingDays(allocation);

        Assert.AreEqual(10, result);

    }

    [TestMethod]
    public void CalculateWorkingDaysWithBankHoliday()
    {

        //Holiday
        var allocation = new Allocation { 
            StartDate = new DateTime(2013, 1, 7), 
            EndDate = new DateTime(2013, 1, 18) 
        };
        var publicHoliday = new List<PublicHoliday> { 
            new PublicHoliday { CountryId = 1, StartDate = new DateTime(2013, 1, 10), 
            Name = "My Bank Holiday" } 
        };
        var user = new User { CountryId = 1 };

        var mock = new Mock<IPublicHolidayRepository>();
        mock.Setup(s => s.Enumerable()).Returns(publicHoliday.AsEnumerable());


        allocation.User = user;

        var allocationLogic = new AllocationLogic(null,mock.Object);

        int result = allocationLogic.CalculateWorkingDays(allocation);

        Assert.AreEqual(9, result);


    }
}
4

2 回答 2

1

我的问题是可以在 CalculateworkingDays 方法中创建 publicHolidayLogic 类的实例,通过 Allocation 构造函数传入所需的存储库吗?或者我应该在分配构造函数中将接口传递给 publicholidaylogic。

后者。您不想将一个实现耦合到另一个实现。在您的世界中,您与合同相结合,然后继续这样做。

很有可能不是传递存储库

public AllocationLogic( IAllocationRepository allocationRepo, 
                        IPublicHolidayRepository publicHolidayRepository )
...

你最终会得到传递服务

public AllocationLogic( IPublicHolidayLogic publicHolidayService )
...
于 2013-11-12T11:20:03.157 回答
0

您将关注点分离与耦合混淆了。通过在另一个中创建一个实例,您将 PublicHolidayLogic 与 AllocationLogic 紧密耦合。

实际上,所有 AllocationLogic 需要的是访问该方法。将 AllocationLogic 的构造函数更改为具有额外的类型参数Func<int, int, IEnumerable<PublicHoliday>>并将其存储在具有相同类型的私有字段中,例如称为_publicHolidayFunc. 然后在创建这两个类的代码中,执行以下操作:

var publicHoliday = new PublicHolidayLogic(publicHolidayRepo);
var allocationLogic = new AllocationLogic(allocationRepo, 
                                          publicHolidayRepo, 
                                          publicHoliday.PublicHolidaysForTheYear);
...

最后把方法改成:

if (_publicHolidayRepository != null)
{
    var holidays = _publicHolidayFunc(allocation.StartDate.Year, allocation.User.CountryId);

    if (_holidays.Count() > 0)
    {
        ...

然后,您将使用 DI 注入所需的方法,从而将两个类彼此分离。

于 2013-11-12T10:54:45.577 回答