0

I have a big project and I'm using the Model pattern for my objects, so I have something like this:

public class Test
{
    public int TestID { get; set; }
    public int StudentID { get; set; }
    public Student Student { get; set; }
    public IList<Result> Results { get; set; }

    public bool StartTest()
    {
        //Logic and rules for starting a test here
    }

    public bool FinishTest()
    {
        //Save the results in the DB            
    }
}

When a student's about to start or finish a test, I have to consume a service depending on the city/state he's in, and apply some specific rules by city/state, if any.

public bool FinishTest()
{
    switch(Address.City.Code)
    {
        case "TO": //My country's state codes
        {
            State_TO state = new State_TO();
            bool status = state.AttemptFinishTest(this);
            //Sending this Test class to the City/State object so it can fetch any information about this and/or set it's rules, if any.

            //Check the return, proceed
        }
    }
}

//Somewhere else
public class State_TO
{
    public bool AttemptFinishTest(Test testObject)
    {
        //external access
    }
}

The problem starts here, I want to separate the main Test project and each state/city classes so it's like this:

//Solution Explorer 
Project.Models //where the models/logic are
Project.State.TO //a state
Project.State.RO //another state
Project.State.SI //etc

This is because the states are still coming up and implementations are still on progress, and to separate the logic of each state from the models as it's much more likely the state rules to change than the model logic (our process shouldn't never change - how we save and manage tests) so we don't have to recompile the DLL whenever any state change.

This way, I hope to get a simple change in a state rule to simply recompile the state's DLL and deploy without changing anything else.

The circular dependency happens because I need to access the Models from the State code because I don't know what kind of information they'll require or operations they'll perform with the tests, and I need the Models to have a reference to the States so they can call the appropriate state code for a test.

One solution I was going to try is to create an interface for the Models, and have the States reference it:

   Models Interface
    /            \
Models---------->States

Then I could call from the Models:

public class Test : ITest
{
    public bool FinishTest()
    {
        State state = GetState(Address.City.Code);
        bool status = state.AttemptFinishTest(this);
    }
}

//And in the State code
public class State_TO
{
    public bool AttemptFinishTest(ITest testInterface);
    {
        //I can access everything through the interface
    }
}

The problem of this solution is that the Models are really big and have a bunch of subclasses, such as Student/Instructor and these have their own subclasses (Addresses, Licenses, etc) and so on, meaning I'd need to create interfaces for the entire project and it'll come with the inconvenience to always change in both places, the Model and the Interface, whenever something changes.

Is there a better, more elegant solution than this? I only need to figure a way to call the proper State class (from an interface maybe), other than that, nothing else is required from the Models project. Is there any way I can do this?

Danicco
  • 1,573
  • 2
  • 23
  • 49
  • Why are you afraid of recompiling DLLs? – C Bauer Nov 20 '14 at 15:08
  • @CBauer The project's really, really big, and recompiling everything for a simple change in a specific state's rule is unfeasible. This is a new project so each state is still coming up with their rules and are prone to change often, and as more and more states implementations appear I don't want to recompile everything. I'm trying to do this so the project remains independent of whether the state is implemented or not (we'll still keep the records in our DB). – Danicco Nov 20 '14 at 15:12

2 Answers2

1

In Service Oriented Architecture you must have your service classes differentiated of your model classes.

So you usually have a Domain library with all definitions of model classes:

public class Test
{
    public int TestID { get; set; }
    public int StudentID { get; set; }
    public Student Student { get; set; }
    public IList<Result> Results { get; set; }
}

and a Service library:

public class TestService : ITestService 
{
    public bool StartTest(int testId)
    {
        //Logic and rules for starting a test here
    }

    public bool FinishTest(int testId)
    {
        //Save the results in the DB            
    }
} 

The interfaces of your services could be also defined in you Domain library

interface  ITestService
{
  Test GetById(int testId);
  bool StartTest(int testId);
  bool FinishTest(int testId);
}

the only dependency is Services -> Domain.

DaniCE
  • 2,412
  • 1
  • 19
  • 27
0

Take a look at dependency injection or Inversion of control. Demos and pattern info. Plenty of examples and explanations.

You use and Interface defintion in a core layer.

The dependency is defined and passed into that layer. The other project references the project with the interface definition. The target layer does NOT reference the outer layer.

So outer layer can change implementation and all still works. Since it pass in a object that complies with the interface definition.

phil soady
  • 11,043
  • 5
  • 50
  • 95