6

Imagine I have an interface:

public interface MyInterface
{
    void CallMeFirst();
    void CallMeDuringApplicationLifecycle();
    void CallMeOnApplicationExit();
}

What is the best way of enforcing the order in which the methods on this interface are consumed by calling code?

It should be an exception if the methods are called in the wrong order.

It should also be an exception if any of the methods are not called at all.

6
  • Do you have working code? If so, post your question on codereview.stackexchange.com
    – rory.ap
    Mar 9, 2016 at 15:00
  • Thanks for the link @roryap. I wasn't aware of the code review site - looks useful. However, this question is more of a generic issue that I come across quite freqently; is there a pattern that I could use to enforce how an interface is consumed. Mar 9, 2016 at 15:09
  • 2
    This looks like an interesting question I'd ask on Software Engineering. The issue is that you have temporal coupling, and the purpose of an interface isn't to enforce anything other than the presence of a given set of members. There is no way an interface can enforce anything like you're asking, let alone throw exceptions. Mar 9, 2016 at 15:13
  • 1
    Interfaces expose an ... interface. Not a process. You are talking about process management. This can be handled by a workflow, a state machine, or many other mechanisms Mar 9, 2016 at 15:14
  • 1
    Does this answer your question? How to make sure people call methods in the right order?
    – gnat
    Dec 16, 2022 at 22:21

4 Answers 4

6

What is the best way of enforcing the order in which the methods on this interface are consumed by calling code?

You can't. Even if your implementations enforce exceptions, you can't guarantee others will.

Methods that care about their order have what is called temporal coupling, which adds a pile of fragility to the code. Where possible, you should redesign the code so that the methods can act independently.

That said, there are some things you can do in certain situations:

  1. Use an abstract base class. You can then enforce some behaviors while leaving others abstract for implementers to supply.

  2. Have multiple classes. When you call the first method, it returns a new object that lets you do the second step. The second method returns a new object that lets you take the third step, and so on.

None of those solve the "if no methods are called" scenario - you necessarily need something to check, but without more details I'm not sure how to approach that problem.

1
  • 1
    The multiple classes / multiple interfaces scheme seems like the most watertight.
    – Mike
    Mar 11, 2016 at 3:15
6

A neat solution would be:

public interface First 
{
    Second doFirst();
}

public interface Second
{
    Third doSecond();
}

public interface Third 
{
    void doThird();
}

One might call:

FirstFactory.create()
    .doFirst()
    .doSecond()
    .doThird();

but cannot call:

FirstFactory.create()
    .doFirst()
    .doThird()
    .doSecond();

Another technical solution (but pretty bad from design perspective):

public interface MyInterface
{
    First CallMeFirst();
    Second CallMeDuringApplicationLifecycle(First first);
    void CallMeOnApplicationExit(Second second);
}

and make somehow First and Second inner classes of the implementing class of MyInterface. The call could be:

CallMeOnApplicationExit(CallMeDuringApplicationLifecycle(CallMeFirst()));
4

Maybe consider the Template Method design pattern. Your design introduces temporal coupling, which introduces risk and could be considered to be a design flaw.

4

m3th0dman showed the general principle, but his solution doesn't quite fit the problem as I understand it, since your method names make me think that CallMeDuringAPplicationLifecycle can be called multiple times.

In C#, a resource that needs cleanup (such as flushing buffers or closing connections) should use implement IDisposable.

interface IConnectionFactory
{
  IConnection connect(); // This is CallMeFirst
}

interface IConnection : IDisposable
{
  void send(); // This is CallMeDuringApplicationLifecycle
}
// And the Dispose() method of IDisposable is CallMeOnApplicationExit.

This way, you enforce that CallMeFirst is called first, because there's no other way to obtain an IConnection. And because C# programmers recognize IDisposable, they know that they have to call Dispose when they're done with the connection. You cannot actually enforce this in C#, so this is as close as you can get. (You can also write a finalizer that checks that Dispose was called, but you can't do anything but log the mistake there, and there's no guarantee that finalizers will be called.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.