Ответ 1
С моей точки зрения, проблема в том, что ни LinkCommandHandler, ни LinkCommandValidator не должны извлекать пользователя GitHub в первую очередь. Если вы думаете о принципах единой ответственности, валидатор имеет одно задание, чтобы проверить существование пользователя, а LinkCommandHanlder имеет одно задание для загрузки объекта в репозиторий. Ни у кого из них не должно быть работы по вытаскиванию Entity/User из GitHub.
Мне нравится структурировать свой код в следующем шаблоне, каждый из которых представляет собой атрибутивный слой. Каждый слой может говорить со слоем выше и ниже, но он не может пропустить слой.
- Уровень данных - это источник данных, такой как база данных или служба, обычно вы не пишете код для этого, вы просто потребляете его.
- Access Layer - представляет собой код для взаимодействия с datalayer
- Peristence Layer - это код, позволяющий получать элементы, готовые для вызова уровня доступа, такие как перенос данных, создание объектов из данных или группирование нескольких вызовов на уровень доступа в один запрос для извлечения данных или хранения данные. Кроме того, решение о кешировании и механизмы кэширования и очистки кэша будут находиться на этом уровне.
- Processor Layer - это код, который выполняет бизнес-логику. Также вы можете использовать валидаторы, другие процессоры, парсеры и т.д.
И затем я сохраняю все вышеописанное отдельно от своего уровня представления. Концепция заключается в том, что основной код и функциональность не должны знать, используется ли он с веб-сайта или настольного приложения или службы WCF.
Итак, в вашем примере у меня будет объект GitHubLinkProcessor метод LinkUser (имя пользователя строки). Внутри этого класса я бы создавал экземпляр класса GitHubPeristenceLayer и вызывал его метод FindUserByName (string username). Затем мы переходим к созданию экземпляра класса GitHubUserValidator для проверки того, что пользователь не является нулевым, и все необходимые данные присутствуют. Проводится одна проверка, создается объект LinkRepositoryPersistence и передается GitHubUser для сохранения в AccessLayer.
Но я хочу особо отметить, что это именно так, как я бы это сделал, и ни в коем случае я не хочу подразумевать, что другие методологии менее справедливы.
EDIT:
Я собирался сделать простой ответ, потому что боялся, что мой ответ уже слишком длинный и скучный. =) Я собираюсь разбить волосы здесь на мгновение, поэтому, пожалуйста, несите меня. Для меня вы не проверяете пользователя, вызывая Git. Вы проверяете наличие удаленного ресурса, который может или не может потерпеть неудачу. Аналогом может быть то, что вы можете подтвердить, что (800) 555-1212 является допустимым форматом для американского номера телефона, но не того, что номер телефона существует и принадлежит правильному человеку. Это отдельный процесс. Как я уже сказал, это расщепление волос, но тем самым он позволяет описать общий код кода.
Итак, пусть ваш локальный пользовательский объект имеет свойство для UserName и Email, которое не может быть null. Вы бы подтвердили это и только перейдете к проверке ресурса, если эта проверка была правильной.
public class User
{
public string UserName { get; set; }
public string Email { get; set; }
//git related properties
public string Login { get; set; }
public string AvataUrl { get; set; }
}
//A processor class to model the process of linking a local system user
//to a remote GitHub User
public class GitHubLinkProcessor()
{
public int LinkUser(string userName, string email, string gitLogin)
{
//first create our local user instance
var myUser = new LocalNamespace.User { UserName = userName, Email = email };
var validator = new UserValidator(myUser);
if (!validator.Validate())
throw new Exception("Invalid or missing user data!");
var GitPersistence = new GitHubPersistence();
var myGitUser = GitPersistence.FindByUserName(gitLogin);
if (myGitUser == null)
throw new Exception("User doesnt exist in Git!");
myUser.Login = myGitUser.Login;
myUser.AvatorUrl = myGitUser.AvatarUrl;
//assuming your persistence layer is returning the Identity
//for this user added to the database
var userPersistence = new UserPersistence();
return userPersistence.SaveLocalUser(myUser);
}
}
public class UserValidator
{
private LocalNamespace.User _user;
public UserValidator(User user)
{
this._user = user;
}
public bool Validate()
{
if (String.IsNullOrEmpty(this._user.UserName) ||
String.IsNullOrEmpty(this._user.Email))
{
return false;
}
}
}