0

I have a scenario where I need to return a list of actions and represent them on a context menu.

The software has a standard list of actions, e.g:

  • Analyse
  • Design
  • Develop
  • Implement

I am tasked with extending the original software for a different client, who would like to add an extra action, e.g.:

  • Analyse
  • Design
  • Develop
  • Test
  • Implement

I would like to develop this conforming to the OCP, so I have written the following factory class:

internal class ActionFactory
{
    public IList<Action> Create()
    {
        var actionProvider =
            Composition.Entity.CreateProvider<ActionProvider, Client>()[CurrentlyRunningClient];

        return
            actionProvider != null
            ?
            StandardActions.Concat(actionProvider.AdditionalActions).ToList()
            :
            StandardActions;
    }

    private IList<Action> StandardActions
    {
        get
        {
            return
                new Action[]
                {
                    new Analyse(),
                    new Design(),
                    new Develop(),
                    new Implement()
                }
                .ToReadOnlyCollection();
        }
    }
}

The ActionProvider will seek out anything that implements a certain interface using reflection, returning me this class (if running the client that requires the new action):

internal class ActionProvider
{
    public IList<MedicationAction> AdditionalActions
    {
        get
        {
            return new Action[]
            {
                new Test()
            }
            .ToReadOnlyCollection();
        }
    }
}

As far as conforming to OCP goes -- so far, so good! If anyone else wants to introduce a new action, then they don't have to modify any existing code. But the factory returns the standard list of actions with any new ones just tagged onto the end.

How would I specify an order for these actions without having to write some sort of class that would know about every possible action? (as I see it, violation of the OCP).

amarsha4
  • 453
  • 6
  • 21
  • 2
    You could give every action a property that indicates how 'important' that feature is and then sort the list in order of that – Kris Apr 20 '17 at 12:03
  • I did consider giving each item a sort of 'weighting' but I'm not sure it's ideal. In fact, adding a new action in this scenario could potentially involve having to change every other action (if the new action had to come first). – amarsha4 Apr 20 '17 at 12:07
  • 3
    What would happen if tomorrow another client will come and say he doesn't need the design or analyse actions? – Ofir Winegarten Apr 20 '17 at 12:08
  • 1
    Also, if you go down with the importance property, then start from 5 with jumps of 5. That way when a new action will come you have enough space for it. – Ofir Winegarten Apr 20 '17 at 12:10
  • @OfirWinegarten I did consider that too! But it seems a little hacky :( And as for the possibility of removing actions... this is also something I thought about and I just pray never happens! I think maybe this means that it would be preferable to have an enum somewhere that contained all the possible actions. That way, I could maintain a standard order, and also add or exclude actions as needed. It seems to be a violation of OCP, but it would only involve future changes modifying one file (the enum). – amarsha4 Apr 20 '17 at 12:12
  • 3
    @amarsha4 Why don't you just save the setup of actions for each client in the DB? This way you are free to do anything. – Ofir Winegarten Apr 20 '17 at 12:14
  • @OfirWinegarten This is not a bad idea. I think I'll consider the pros/cons of a central list over a DB call. – amarsha4 Apr 20 '17 at 12:23
  • I think Ofir's idea of setup in the DB is fine. You could also use enums for this if you didn't want to call the DB. You still get your static typing, but an enum isn't a class, so the OCP doesn't apply. It's kind of a loophole, but also what I believe enums were created for. – Jon S Apr 20 '17 at 13:10
  • How many clients do you have? If the default action list gets updated does it have to reflect on every clients? Could some clients not want any of the defaults? As for the ordering you may use a simple float which would pretty much gives you the ability to insert in between any existing actions without changing the order of other actions. You could also use a linked-list or something like that. – plalx Apr 29 '17 at 21:15
  • @OfirWinegarten I agree. Why overthink! Just pass client id, select actions, display menu, go home and sleep. :) KISS principle. – Nikhil Vartak May 23 '17 at 18:21

0 Answers0