I am a beginner in Design Patterns.
Suppose I am developing a C# application to track the development works performed by various members in development team (i.e. a Project Tracker).
I am trying to be inspired by Strategy Pattern.
So I am designing my classes and interfaces as follows:
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
{
}
What things should I do to improve this design?
Well, first off, what you have there is not an instance of a Strategy pattern. The Strategy Pattern allows for the dynamic specification of a method for getting things done. What you have here is really more of a standard interface design, where you allocate responsibilities and abilities by interface inheritance.
Edit: Let's use an example. Let's say that you have a group of Workers; you also have a set of Tasks. Each Worker can perform a Task. These Tasks can consist if several things, such as DoFoo() and DoBar(). Each Worker does not know what Task they will perform; they just know when they show up that they will do a Task.
So we'll want to model Workers as having a Task that they will perform. Since the Tasks vary widely, we'll implement the Task as an interface.
So we'll have:
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();
}
}
}
So what happens is that when we instantiate a Job
, the Job
creates two Worker
s. The first Worker
has a Task1
task; the second Worker
has a Task2
task. To make the Worker
s do their Task
s, we call the DoJob()
method on the Job
class, which just calls the DoWork()
method on each of the Worker
s, which in turn calls the DoTask()
method on each of the Task
s that the Worker
s were set with.
If we want to change the Worker
s to all do Task1
, we call the ChangeJobsToTask1()
method, which sets the Task
to Task1
for all of the Worker
objects contained by the Job
; if, at that point, we call the DoJob()
on the Job
object, all the Worker
s will perform the Task1
task. Similarly, if we want to change the Task
s to Task2
, just call the ChangeJobsToTask2()
method; all the Worker
s will then execute the Task2.DoTask()
when their DoWork()
method is called.
The important point of abstraction here is that the Worker
s expose a DoWork()
method, but they do not necessarily know what work it is that is being done. That is, the Task
s for the Worker
s are interchangeable; the Worker
s just know that they're going to do a Task
, but the specifics of what it is are unimportant to the Worker
s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With