提问人:Yusuf 提问时间:11/17/2023 更新时间:11/17/2023 访问量:55
在此代码中找不到只是重构代码的错误 [已关闭]
Cant find a bug in this code that is just refactored code [closed]
问:
我有一段 C# 代码,我打算重构并使其变得更好 - 遵守 SOLID、DRY、KISS 等标准。原始代码为:
public class CustomerService
{
public bool AddCustomer(string firname, string surname, string email, DateTime dateOfBirth, int companyId)
{
if (string.IsNullOrEmpty(firname) || string.IsNullOrEmpty(surname))
{
return false;
}
if (!email.Contains("@") && !email.Contains("."))
{
return false;
}
var now = DateTime.Now;
int age = now.Year - dateOfBirth.Year;
if (now.Month < dateOfBirth.Month || (now.Month == dateOfBirth.Month && now.Day < dateOfBirth.Day)) age--;
if (age < 21)
{
return false;
}
var companyRepository = new CompanyRepository();
var company = companyRepository.GetById(companyId);
var customer = new Customer
{
Company = company,
DateOfBirth = dateOfBirth,
EmailAddress = email,
Firstname = firname,
Surname = surname
};
if (company.Name == "VeryImportantClient")
{
// Skip credit check
customer.HasCreditLimit = false;
}
else if (company.Name == "ImportantClient")
{
// Do credit check and double credit limit
customer.HasCreditLimit = true;
using (var customerCreditService = new CustomerCreditServiceClient())
{
var creditLimit = customerCreditService.GetCreditLimit(customer.Firstname, customer.Surname, customer.DateOfBirth).Result;
creditLimit = creditLimit*2;
customer.CreditLimit = creditLimit;
}
}
else
{
// Do credit check
customer.HasCreditLimit = true;
using (var customerCreditService = new CustomerCreditServiceClient())
{
var creditLimit = customerCreditService.GetCreditLimit(customer.Firstname, customer.Surname, customer.DateOfBirth).Result;
customer.CreditLimit = creditLimit;
}
}
if (customer.HasCreditLimit && customer.CreditLimit < 500)
{
return false;
}
CustomerDataAccess.AddCustomer(customer);
return true;
}
}
}
我将其重构如下:
public bool AddCustomer(string firname, string surname, string email, DateTime dateOfBirth, int companyId)
{
if (!_customerValidator.ValidateCustomer(firname, surname, email, dateOfBirth))
{
return false;
}
var company = _companyRepository.GetById(companyId);
var customer = _customerFactory.CreateCustomer(firname, surname, email, dateOfBirth, company);
customer.HasCreditLimit = _creditLimitCalculator.AssessCreditLimit(company.Name);
customer.CreditLimit = _creditLimitCalculator.RetrieveCreditLimit(customer);
if (!_creditLimitValidator.HasCreditLimit(customer))
{
return false;
}
_customerDataAccessFactory.AddCustomer(customer);
return true;
}
}
我基本上希望类只调用方法以尽可能多地满足 SOLID 和 DRY。
当我提交此代码时,它是根据一系列未提供给我们的测试来判断的,我被告知的错误是:
There was a mistake that made the credit check work in reverse, which broke business logic.
处理它的新代码的相关部分只是从原始代码中剥离出来,基本上在这里:
public class CreditLimitCalculator : ICreditLimitCalculator
{
public bool AssessCreditLimit(string companyName)
{
if (companyName == Company.VeryImportantClient)
{
return true;
}
return false;
}
public int RetrieveCreditLimit(Customer customer)
{
int creditLimit;
switch (customer.Company.Name)
{
case Company.VeryImportantClient:
creditLimit = customer.CreditLimit;
break;
case Company.ImportantClient:
using (var customerCreditService = new CustomerCreditServiceClient())
{
var limit = customerCreditService.GetCreditLimit(customer.Firstname, customer.Surname, customer.DateOfBirth).Result;
limit *= 2;
creditLimit = limit;
}
break;
default:
using (var customerCreditService = new CustomerCreditServiceClient())
{
var limit = customerCreditService.GetCreditLimit(customer.Firstname, customer.Surname, customer.DateOfBirth).Result;
creditLimit = limit;
}
break;
}
return creditLimit;
}
}
和:
public bool HasCreditLimit(Customer customer)
{
if (customer.HasCreditLimit && customer.CreditLimit < 500)
{
return false;
}
return true;
}
它基本上是完全相同的代码,只是移动到不同的类中,所以我不知道为什么它失败了。它也无法初始化,因此也无法调试和单步执行它。有什么建议吗?
答:
我认为访问客户的 CreditLimit 会触发测试工具中的行为,这被认为是不正确的,因为在公司非常重要的情况下,原始代码没有
在您的代码中,您可以设置信用额度,而不管公司的评估如何:
customer.CreditLimit = _creditLimitCalculator.RetrieveCreditLimit(customer);
您的 RetrieveCreditLimit(customer) 方法返回客户。非常重要公司的信用额度:
case Company.VeryImportantClient:
creditLimit = customer.CreditLimit;
break;
在这种情况下,简化为
customer.CreditLimit = customer.CreditLimit;
现在,我同意这看起来是良性的,但我们无法分辨是什么客户。CreditLimit 初始化为,或者 set/get 访问器是否执行比访问基础属性更复杂的操作。例如,如果他们在某处触发了某些操作 - 例如,监视设置/访问客户信用额度的尝试,那么它将围绕此代码向系统公开一组不同的调用,因为:
在原始代码中,在公司非常重要的情况下,不会尝试设置或获取客户。信用额度:
if (company.Name == "VeryImportantClient")
{
// Skip credit check
customer.HasCreditLimit = false;
}
即使在原始代码的末尾,也不会计算下面的第二句:
if (customer.HasCreditLimit && customer.CreditLimit < 500)
{
return false;
}
所以我最初的猜测是,访问客户的 CreditLimit 会触发测试工具中的行为,这被认为是不正确的,因为在公司 VeryImportant 的情况下,原始代码没有
您是否有权访问 Customer 类源代码?它是否对访问 CreditLimit 做了什么特别的事情?
如果客户有 CreditLimit,您可以尝试仅设置 CreditLimit 吗?
if (customer.HasCreditLimit)
{
customer.CreditLimit = _creditLimitCalculator.RetrieveCreditLimit(customer);
}
评论
.Result
if(condition) {return true;} return false;
return condition;
if (customer.Name == "yadda") ...