“Патерн Вівторка” #15: Команда (Command)
|Ваш босс дуже вимогливий чувак – він ніколи не переймається тим як буде робитися робота і не особливо переймається хто її буде робити – йому головне щоб вона була зроблена як тільки замовник дасть добро. Проте вашому босу ніхто не мішає назначати людей які будуть працювати над роботою. Він вирішив що ви, оскільки ви на високих позиціях у компанії, ідеально підходете для того щоб зібрати бригаду Z, отримати список вимог від замовника і бути готовими запустити роботу людьми із Z, як тільки замовник підпише контракт.
КОМАНДА
Команда – це такий дизайн патерн, що дозволяє інкапсулювати всю інформацію, необхідну для виконання певних операцій пізніше у коді.
В нашому прикладі ви є Командою (Command) – тому що ви інкапсулюєте справжню робочу групу Z, і параметри необхідні для старту роботи (проект і вимоги). Бригада, що є Отримувачем (Receiver) і вимоги, параметри, були вам передані вашим босом – Клієнтом (Client).
Замовник має контакт до вас і може попросити виконати вас усю необхідну їм роботу як тільки запуститься процес після підписання контракту. Замовник це ваш Запускач (Invoker), він знає як попросити вас виконати роботу, але вся робота і виконавці були вже сформовані.
Клієнтський код (Client)
А зараз трошки глянемо на код. Ось клієнський код, – ваш босс:
var customer = new Customer();
// із певних міркуваня, босс завжди знає, що грошей стає тільки
// на бригаду Z
var team = new Team("Z");
// він також отримав список вимог, що треба буде передати бригаді
var requirements = new List<Requirement>() {
new Requirement("Cool web site"),
new Requirement("Ability to book beer on site") };
// ви повинні бути готові бути викликаним замовником
ICommand commandX = new YouAsProjectManagerCommand(team, requirements);
customer.AddCommand(commandX);
// в компанії також є програміст-герой, що кодує на швидкості світла
var heroDeveloper = new HeroDeveloper();
// босс вирішив віддати йому проект A
ICommand commandA = new HeroDeveloperCommand(heroDeveloper, "A");
customer.AddCommand(commandA);
// як тільки замовник підписує контракт із вашим боссом
// ваша бригада і програміст-герой готові виконати все що треба
customer.SignContractWithBoss();
Команда (Command)
Тут просто глянемо як виглядають конкретні реалізації команд:
public interface ICommand
{
void Execute();
}
public class YouAsProjectManagerCommand : ICommand
{
public YouAsProjectManagerCommand(Team team, List<Requirement> requirements)
{
Team = team;
Requirements = requirements;
}
public void Execute()
{
// реалізація делегує роботу до потрібного отримувача
Team.CompleteProject(Requirements);
}
protected Team Team { get; set; }
protected List<Requirement> Requirements { get; set; }
}
public class HeroDeveloperCommand : ICommand
{
public HeroDeveloperCommand(HeroDeveloper heroDeveloper, string projectName)
{
HeroDeveloper = heroDeveloper;
ProjectName = projectName;
}
protected HeroDeveloper HeroDeveloper { get; set; }
public string ProjectName { get; set; }
public void Execute()
{
// реалізація делегує роботу до потрібного отримувача
HeroDeveloper.DoAllHardWork(ProjectName);
}
}
Отримувач (Receiver)
Team та HeroDeveloper є отримувачами роботи, що має бути зроблена.
Запускач (Invoker)
Замовник насправді не дуже переймається хто буде робити його роботу, але він чітко хоче її зробити – він викликає метод Execute.
public class Customer
{
public Customer()
{
Commands = new List<ICommand>();
}
public void AddCommand(ICommand command)
{
Commands.Add(command);
}
protected List<ICommand> Commands { get; set; }
public void SignContractWithBoss()
{
foreach (var command in Commands)
{
command.Execute();
}
}
}
Вивід
User Story (Cool web site) has been completed
User Story (Ability to book beer on site) has been completed
Hero developer completed project (A) without requirements in manner of couple of hours!
Ага, а ще дайте мені знати чи взаємодія між цими всіма класами є зрозуміла і чи тут не бракує якоїсь UML-діаграми.