2009-06-19 6 views
6

Я новичок в дизайне.Дизайн Шаблоны - шаблон стратегии

Предположим, я разрабатываю приложение C# для отслеживания работ по разработке, выполняемых различными членами команды разработчиков (т. Е. Tracker Project).

Я стараюсь вдохновляться шаблоном стратегии.

Так я проектирования мои классы и интерфейсы следующим образом:

interface IEmployee 
{ 
    void Retires(); 
    void TakesLeave(); 
} 

interface IResponsible 
{ 
void AcknowledgeJobAccomplish(); 
void CompletesJob(); 
} 

interface ILeader 
{ 
    void FormsTeam(); 
    void RecruitsNewMember(); 
    void KicksOutMemberFromTheTeam(); 
    void AssignsJob(); 
void UnassignsJob(); 
void QueriesTheJobStatus(); 
void ChangesTheJobStatus(); 
} 

interface IPersistent 
{ 
    void Save(); 
    void Update(); 
    void Delete(); 
} 

abstract class TeamMember : IEmployee, IResponsible, IPersistent 
{ 
    string Name; 
} 

class Programmer : TeamMember 
{ 
} 

class LeadProgrammer : Programmer, ILeader 
{ 
    ProgrammerCollection associateProgrammers; 
} 

class ProjectManager : TeamMember, ILeader 
{ 
    TeamMemberCollection teamMembers; 
} 

abstract class Tester : TeamMember 
{ 
} 

class UnitTester : Tester 
{ 
} 

class QC : Tester 
{ 
} 

class SupportStaff : TeamMember 
{ 
} 

Какие вещи я должен сделать, чтобы улучшить эту конструкцию?

+0

TeamMamber: командный игрок (пишется ошибка, я думаю) –

ответ

8

Ну, во-первых, у вас там нет экземпляра шаблона стратегии. Strategy Pattern позволяет динамическую спецификацию метода для выполнения. То, что у вас здесь, - это действительно более стандартный дизайн интерфейса, где вы распределяете обязанности и способности с помощью наследования интерфейса.

Редактировать: Давайте использовать пример. Предположим, что у вас есть группа Рабочих; у вас также есть набор задач. Каждый Рабочий может выполнять Задачу. Эти Задачи могут состоять из нескольких вещей, таких как DoFoo() и DoBar(). Каждый Рабочий не знает, какую Задачу они будут выполнять; они просто знают, когда обнаруживают, что они будут делать Задачу.

Таким образом, мы хотим, чтобы Рабочие работали с задачей, которую они будут выполнять. Поскольку задачи различаются в широких пределах, мы реализуем задачу как интерфейс.

Таким образом, мы будем иметь:

public class Worker 
{ 
    public Task myTask; 

    public Worker(Task task) 
    { 
     myTask = task; 
    } 

    public void DoWork() 
     { 
     myTask.DoTask(); 
     } 
    } 
} 

Interface Task 
{ 
    void DoTask(); 
} 

public class Task1 : Task 
{ 
    public void DoTask() 
    { 
    // Do whatever Task1 will do 
    } 
} 

public class Task2 : Task 
{ 
    public void DoTask() 
    { 
    // Do whatever Task2 will do 
    } 
} 

public class Job 
{ 
    public List<Worker> workers; 

    public void Job() 
    { 
     workers.Add(new Worker(new Task1())); 
     workers.Add(new Worker(new Task2())); 
    } 

    public void DoJob() 
    { 
     foreach (Worker worker in workers) 
     { 
     worker.DoWork(); 
     } 
    } 

    public void ChangeJobsToTask1() 
    { 
     foreach (Worker worker in workers) 
     { 
     worker.myTask = new Task1(); 
     } 
    } 

    public void ChangeJobsToTask2() 
    { 
     foreach (Worker worker in workers) 
     { 
     worker.myTask = new Task2(); 
     } 
    } 
} 

Так что же происходит, что, когда мы создаем Job, то Job создает два Worker с. Первый Worker имеет задание Task1; второй Worker имеет задание Task2. Для того, чтобы Worker s сделать их Task с, мы называем DoJob() метод на Job класса, который только называет DoWork() метод на каждом из Worker с, что в свою очередь вызывает метод DoTask() на каждом из Task с, что Worker s были установлены с.

Если мы хотим изменить Worker с, чтобы все сделать Task1, мы называем ChangeJobsToTask1() метод, который устанавливает Task к Task1 для всех Worker объектов, содержащихся в Job; если в этот момент мы назовем DoJob() на объекте Job, все Worker s выполнит задачу Task1. Аналогичным образом, если мы хотим изменить Task s на Task2, просто вызовите метод ChangeJobsToTask2(); то все Worker s будут выполнять Task2.DoTask(), когда вызывается их метод DoWork().

Важным пунктом абстракции здесь является то, что Worker s выставляют метод DoWork(), но они не обязательно знают, что это за работа. То есть, Task s для Worker s являются взаимозаменяемыми; Worker s просто знают, что они собираются сделать Task, но особенности того, что это не имеет значения для Worker.

+0

Из книги Patterns Head First Design, я нашел принцип «Идентифицировать аспекты вашего приложения, которые изменяются и отделить их от того, что остается неизменными». Можете ли вы предложить мне, как мне это сделать? – 2009-06-19 16:51:52

+1

@ JMSA: Я не могу предложить, как это сделать, не зная всего о вашем приложении, но я добавлю информацию в ответ, чтобы проиллюстрировать пример. –

+0

Из всех этих обсуждений я действительно нашел, что мой пример не идеален для реализации Стратегического шаблона. Не так ли? – 2009-06-19 18:08:41

2

Я не вижу шаблон стратегии в вашем примере. Стратегический шаблон принимает класс «стратегия» (обычно наследуется от интерфейса с помощью логического метода, например «DoJob()») в параметре, и когда вызывается метод, он будет выполнять операцию, применяя ранее пройденную стратегию, не зная, что это будет конкретно делать.

В вашем примере у вас может быть класс, наследуемый всеми вашими людьми, у которого есть SetJob (IJobStrategy), и есть метод DoJob(), который вызовет интерфейс DoJob() (из IJobStrategy). Тогда вы можете иметь несколько конкретных заданий, которые наследуют IJobStrategy. Таким образом, ваши люди не знают работу, и вы можете изменить работу, не изменяя класс человека.

Вы можете увидеть пример и дополнительную информацию here.

0

Это похоже на Принцип разделения сегрегации. Теперь это хорошо работает со стратегией, но вот что я делаю иначе.

Тестер не будет классом Concrete, это будет TeamMember с TesterCompletesJobStrategy, настроенным как это CompletesJobStrategy. В конце концов, единственное, что удерживает меня от тестирования, - это моя назначенная задача в команде.

Как раз говорящий, я бы начал с чего-то более подобного, если бы был нацелен на Стратегию.

interface ICompleteJobStrategy { 
    void CompleteJob(IResponsible responsibleParty); 
} 
class TesterCompletJobStrategy : ICompleteJobStrategy { 
    ... 
} 
class TeamMember : IResponsible { 
    TeamMember(ICompleteJobStrategy strat){ .. }; 
    void CompleteJob() { _completeJobStrategy.CompleteJob(this) ; } 
} 
+0

Вам не нужен «общедоступный» интерфейс –