Skip to content

Separating Concerns

tkellogg edited this page May 3, 2011 · 5 revisions

Separating Concerns

Most challenges of IT programming isn't so much about math & algorithms, it's about managing complexity. Creating fluent workflows is great, but having fluent workflows sprinkled throughout your code leads to unnecessary duplication. Objectflow provides some tools to modularize your workflow logic. The keystone of this abstraction is the workflow mediator.

public class SiteVisitWorkflow : WorkflowMediator<SiteVisit> {
    private IUserContext _context;

    // We need this dependency for enforcing transition security
    public SiteVisitWorkflow(IUserContext context) {
        _context = context;
    }

    /// <summary>
    /// This is where the workflow is defined. The mediator takes care of the
    /// details about caching the definition, so consider this final.
    /// </summary>
    protected override IStatefulWorkflow<SiteVisit> Define() {
        var wf = new StatefulWorkflow<SiteVisit>("Site Visit workflow")
            .Yield("Created")
            
            // Parameterized workflow step
            .Do(ScheduleVisit)
            .Yield("Scheduled")
            
            .Do(x => x.Open())
            .Yield("Opened")
            
            .Do(PrepareForApproval)
            .Yield("Pending")
            
            .Do(x => x.Approve());
            
        return wf;
    }
    
    /// <summary>
    /// This is where security is implemented
    /// </summary>
    public override bool CanDoTransition(object from, object to) {
        if (from == "Pending")
            return _context.IsManager;
        else
            return base.CanDoTransition(from, to);
    }
    
    private void ScheduleVisit(SiteVisit visit, DateTime day) {
        visit.ScheduledDate = day;
    }
    
    private void PrepareForApproval(SiteVisit visit) {
        // some logic
    }    
}

Below is a sample MVC controller that interacts with this workflow. Notice how little knowledge of the workflow is required to have this controller interact with it.

public class SiteVisitController : Controller {
    private IWorkflowMediator<SiteVisit> _workflow;
    private IRepository<SiteVisit> _repo;
    
    public SiteVisitController(IWorkflowMediator<SiteVisit> workflow, IRepository<SiteVisit> repo) {
        _workflow = workflow;
        _repo = repo;
    }

    [HttpPost]
    public ActionResult Submit(int siteVisitId, DateTime day) {
        var visit = _repo.GetById(siteVisitId);
        _workflow.Start(visit, day);
        return View(visit);
    }

    [HttpPost]
    public ActionResult Submit(int siteVisitId) {
        var visit = _repo.GetById(siteVisitId);
        _workflow.Start(visit);
        return View(visit);
    }
}
Clone this wiki locally