Я не знаю WinForms (или EF или действительно .NET для всего, что имеет значение), но я сделаю предложение, основанное на том, что я знаю (или думаю, что могу вспомнить).
ПозволяетПредположим, у вас есть простой класс формы, который рассчитывает риск на основе 3 переменных: возраст, количество и цвет волос.При нажатии кнопки «Оценить» метка будет обновлена соответствующей строкой: «Высокий», «Средний» и «Низкий».
public void btnRate_click() {
var RiskScore = 0;
if(txtAge.Value < 25)
RiskScore += 2;
else if(txtAge.Value < 40)
RiskScore += 1;
if(txtAmount.Value < 2.00)
RiskScore += 10;
else if(txtAmount.Value < 10.00)
RiskScore += 3;
else if(txtAmount.Value < 50.00)
RiskScore += 5;
if(txtHairColor.Value == "Red")
RiskScore += 75;
if(RiskScore < 2)
lblResult.Value = "Low";
else if(RiskScore < 8)
lblResult.Value = "Medium";
else
lblResult.Value = "High";
}
Учитывая этот код, я бы начал с некоторого простого "«Prefactoring» перед постановкой некоторых тестов.Я склонен использовать стандартные рефакторинги, которые IDE, такие как ReSharper, могут выполнять автоматически, потому что они действительно безопасны и редко оставляют нежелательные побочные эффекты.
Первое, что мы сделаем, это удалим дублирование в коде.В частности, путем извлечения некоторых локальных переменных .
public void btnRate_click() {
var RiskScore = 0;
var Age = txtAge.Value;
if(Age < 25)
RiskScore += 2;
else if(Age < 40)
RiskScore += 1;
var Amount = txtAmount.Value;
if(Amount < 2.00)
RiskScore += 10;
else if(Amount < 10.00)
RiskScore += 3;
else if(Amount < 50.00)
RiskScore += 5;
var HairColor = txtHairColor.Value;
if(HairColor == "Red")
RiskScore += 75;
var Result = ""
if(RiskScore < 2)
Result = "Low";
else if(RiskScore < 8)
Result = "Medium";
else
Result = "High";
lblResult.Value = Result;
}
Этот рефакторинг был быстрым и может быть выполнен автоматически с помощью Ctrl+Alt+V
Теперь потребуется немного времени, чтобы немного упорядочить код, переместивобъявления переменных вокруг.
public void btnRate_click() {
var Age = txtAge.Value;
var Amount = txtAmount.Value;
var HairColor = txtHairColor.Value;
var RiskScore = 0;
var Result = ""
if(Age < 25)
RiskScore += 2;
else if(Age < 40)
RiskScore += 1;
if(Amount < 2.00)
RiskScore += 10;
else if(Amount < 10.00)
RiskScore += 3;
else if(Amount < 50.00)
RiskScore += 5;
if(HairColor == "Red")
RiskScore += 75;
if(RiskScore < 2)
Result = "Low";
else if(RiskScore < 8)
Result = "Medium";
else
Result = "High";
lblResult.Value = Result;
}
Теперь нам удалось добиться того, чтобы изолировать бизнес-правила (расчет риска) от компонентов пользовательского интерфейса (элементы управления формой).Следующий шаг - вывести эти бизнес-правила из класса пользовательского интерфейса в другое место.Еще один рефакторинг в порядке.При рассмотрении этого кода в этом методе используются четыре переменные.Когда код работает с одними и теми же переменными, это часто является признаком того, что там скрывается класс.Давайте использовать рефакторинг Object Method Object здесь ... (я не помню этого нажатия клавиши, но я почти уверен, что он там есть)
Глядя на то, что делает этот блок кода,мы назовем этот новый класс RiskCalculator
.После рефакторинга код должен выглядеть примерно так:
public void btnRate_click() {
var Age = txtAge.Value;
var Amount = txtAmount.Value;
var HairColor = txtHairColor.Value;
var Result = new RiskCalculator(Age, Amount, HairColor).Invoke();
lblResult.Value = Result;
}
// In RiskCalculator.cs
public class RiskCalculator {
private int Age;
private double Amount;
private string HairColor;
public RiskCalculator(int Age, double Amount, string HairColor) {
this.Age = Age;
this.Amount = Amount;
this.HairColor = HairColor;
}
public string Invoke() {
var RiskScore = 0;
var Result = ""
if(Age < 25)
RiskScore += 2;
else if(Age < 40)
RiskScore += 1;
if(Amount < 2.00)
RiskScore += 10;
else if(Amount < 10.00)
RiskScore += 3;
else if(Amount < 50.00)
RiskScore += 5;
if(HairColor == "Red")
RiskScore += 75;
if(RiskScore < 2)
Result = "Low";
else if(RiskScore < 8)
Result = "Medium";
else
Result = "High";
return Result;
}
}
Теперь мы кое-что получаем.Ваш RiskCalculator
содержит только бизнес-логику и теперь доступен для тестирования.Следующим шагом является написание калькулятора, проверяющего все бизнес-правила.Это даст вам возможность выполнить рефакторинг и очистить фактический код расчета.
В процессе написания тестов вы можете заметить, что RiskCalculator
не совсем подходит для этого класса.Я имею в виду, если вы думаете об этом, данные, которые передаются в конструктор, фактически представляют ваш кредит!Учитывая, что у вас есть хорошая база тестов для текущего RiskCalculator
, вы можете выполнить несколько рефакторингов Rename.Мы начнем с Метод переименования .
Метод Invoke
действительно неинформативен как имя, поэтому мы переименуем его.Что это делает?Я бы сказал, что на самом деле он выполняет расчет риска, поэтому назовем его calculateRisk
.После этого мы должны спросить себя, для чего он рассчитывает риск.Ответ - кредит, так что это будет наш второй рефакторинг.Мы будем использовать рефакторинг Rename Class, переименовывая RiskCalculator
в Loan
.Это становится нашим первым доменным объектом в системе.
// RiskCalculator.cs has now become Loan.cs
public class Loan {
// ...
public string CalculateRisk() {
// ...
}
}
После каждого из этих рефакторингов тесты должны быть запущены и продолжать проходить.Вы можете продолжить, очистив эту ужасную бизнес-логику в методе CalculateRisk
.
Теперь, когда наш доменный объект очищен, мы можем вернуться к этому обработчику событий, который должен выглядеть примерно так:
public void btnRate_click() {
var Age = txtAge.Value;
var Amount = txtAmount.Value;
var HairColor = txtHairColor.Value;
var Result = new Loan(Age, Amount, HairColor).CalculateRisk();
lblResult.Value = Result;
}
Вероятно, я бы исправил это, выполнив Встроенную временную переменную и рефакторинг Извлечение переменной:
public void btnRate_click() {
var MicroLoan = new Loan(txtAge.Value, txtAmount.Value, txtHairColor.Value);
lblResult.Value = MicroLoan.CalculateRisk();
}
Это довольно чисто сейчас, и кода на самом деле немноготам, чтобы испортить, так что нет особой необходимости в тестах на данный момент.
Надеюсь, это поможет.Я действительно не отвечал на ваши вопросы о репозиториях, но я надеюсь, что это даст вам возможность начать работу.Когда дело доходит до того, куда поместить вашу логику, помните о Принципе единой ответственности , который поможет вам решить, что входит в ваш репозиторий, а что нет.Это также может заставить вас разбить класс Loan
на другие более мелкие, более сфокусированные классы.
Удачи!Brandon