views:

128

answers:

3

I'm aware of these two questions which explain why I can't have a protected/private method in an interface, what I'm trying to work out is how to control from where my methods are called, briefly:

public class EditField : IEditField
{
    public EditField() {}
    public EditField(IStateMachine stateMachine) {}
    public void Action_Commit() {}
    public void Action_Undo() {}
}

Consumers can use the default IStateMachine, or roll their own.

I was wondering if there is any way to ensure that Action_ methods are only called from within an IStateMachine, so that consumers don't start messing around with state stuff. I suspect there's no way of doing this, but wondered if I'm missing something. I'm not a Design Pattern guru.

A: 

I'm not sure I understand what you want to do. But to hide stuff I usually implement interfaces explicitly. If someone needs access to some things and not to others, you should also probably split the interface into two or something.

Svish
+3  A: 

Hmm, what you can do is 'hide' the Action_ methods by implementing those methods explicitly.

If you do this, users can only call those methods when they cast the class back to the interface. It won't prevent them from having the possibilty to call those methods however, but maybe it will make it less obvious that it is possible.

public class EditField : IEditField
{
    public EditField( IStateMachine stateMachine ) {}

    void IEditField.Action_Commit() {}

    void IEditField.Action_Undo() {}

}

By implementing these methods like this, the user will not be able to do this:

EditField ef = new EditField();
ef.Action_Commit(); // compile-error

However, it is possible to call those methods if they do this:

IEditField ef = new EditField();
ef.Action_Commit();

or

EditField ef = new EditField()
((IEditField)ef).Action_Commit();

But, isn't it a better solution / possible to have those Commit & Undo methods a part of your IStateMachine instead ?

And, if you can't modify the design to have those Commit & Undo methods part of the IStateMachine, then maybe you can create an abstract class instead of the IEditField interface ?
In that abstract class, you can make those Action_ methods protected.

Frederik Gheysels
+3  A: 

While you can't have access modifiers on interfaces, but here's one way to hide the members, yet make them accessible to IStateMachine implementors.

public interface IEditActions
{
  void Action_Commit() {}
  void Action_Undo() {}
}

public interface IStateMachine
{
  void Initialize(IEditActions editActions);
}

public class EditField : IEditField
{
  private class EditActions : IEditActions
  {
    EditField _editField;

    public EditActions(EditField editField)
    {
      _editField = editField;
    }

    public void Action_Commit()
    {
      _editField.Action_Commit();
    }
    public void Action_Undo()
    {
      _editField.Action_Undo();
    }
  }

  public EditField() {}
  public EditField(IStateMachine stateMachine)
  {
    stateMachine.Initialize(new EditActions(this));
  }

  private void Action_Commit() {}
  private void Action_Undo() {}
}
Dustin Campbell