6

I have a Bird class. A bird can learn and a bird can fly (methods). A bird can only fly after it learns.

Considering both methods are public. How can you make this clear to another fellow developer. Usually they should take a look at the public method names and understand what they do. But how can he understand without reading comments or understand the encapsulated code that method2 can be called only after method1?

1
  • 1
    Probably a bad idea, but have the Learn() method return a result (what was learned) that is then passed to the Fly() method as a parameter. Commented May 8, 2013 at 20:11

7 Answers 7

15

The cleanest (but not always most practical) way is to have learn return an EducatedBird which can then fly.

I'm not sure if there's a formal pattern named for it, but this sort of pattern works very well for other sorts of state transitions such as opening connections.

2
  • 1
    Nice. This is what I call a State Factory.
    – Reactgular
    Commented May 8, 2013 at 21:41
  • 6
    This is also an example of the Monad pattern; the object produced by one operation encapsulates not only the "result" of that operation, but the possible additional operations that can be performed on the result.
    – KeithS
    Commented May 8, 2013 at 21:53
6

Telastyn's answer is the textbook suggestion, and not a bad one. This is called the state pattern, and can be implemented in most programming languages, but I find it very clunky, and when you start getting into the 10-20 state range, you'll want to have had implemented the pattern as a series of decorators and by the time you're done you'll have foresworn OOP completely.

The state pattern is useful only if you have a clear and distinct number of states and state transitions. If you want to have an arbitrary number of states, or have multidimensional states, you should probably use the decorator pattern. That, though, has its own caveats. Depending on your language, it, too, can be clunky (If you have a method that expects a FlyingBird but you pass a YellowBird that wraps a FlyingBird...). You tend to lose some of your language's benefits by implementing the decorator pattern in this way.

The best way, in my opinion, would be to either implement the state pattern implicitly using an internal state for the object and exception handling, or to composite the object (if your language supports that) at run time.

1
  • 1
    I wouldn't consider my answer a state pattern. The state (in the state pattern) is an object contained within the bird that manages when it can do what. My answer involves 'evolving' different states over time, and better matches Functional Programming's model of mutating state.
    – Telastyn
    Commented May 8, 2013 at 21:19
4

Generally, if I have to enforce at compile-time that one method must happen first, and make it obvious to the coder, I generally either use a monad which is a similar idea to Telastyn's state pattern, or I enforce the use of a token.

Have Learn() return a FlightKnowledge object. This object should have a constructor visibility that precludes the average consumer from creating their own (private, protected, internal etc). Then, expose Fly(FlightKnowledge) as the only overload of the Fly method. This requires the coder to pass in a valid FlightKnowledge object (depending on your language you can either make FlightKnowledge a type that can't be null, or enforce by decoration that the parameter cannot be null), and if the only way he can get one is by calling Learn(), then you've enforced your order of operations.

Just don't turn this into a "King's Quest" anti-pattern (to Fly(), you must have FlightKnowledge, which you get by calling Learn(), which takes a Tuition object that is produced by the MamaBird by calling AskForTuition() which takes a SweetTalk object that's...). If your order of operations is that deep, tokens by themselves are the wrong pattern.

1
  • +1 For the "King's Quest" pattern. Awesome definition :P (And since it is a Sierra-pattern, there is always the possibility of death if you make a mistake!)
    – Andres F.
    Commented May 16, 2013 at 14:15
1

It's evil, but you can use the negative reinforcement method:

 class Bird
   fn learn :  _learned = true
   fn fly : assert(_learned) ...do flying...

   bool _learned = false

The clear disadvantage is lack of compile-time or static type information to guide the developer, but it's been used before, particularly in C.

1
  • 2
    This isn't terrible, or necessarily all that evil. If the assert() call can also take a message string or a specific exception to throw out, this combination of "fail fast" and "scream the relevant error as you die" makes it easier for the coder to learn by trial and error until it works.
    – KeithS
    Commented May 8, 2013 at 22:18
1

You can not close a file unless it's open. How should the close method react when executed in the wrong state? Should it return a failure, or throw an exception. That depends upon the language and programming style you are following.

Weather or not the Bird can fly or not is a representation of it's internal state. The same as a file resource, and as such you would follow the same design patterns. Treating the Bird as having an internal state the the developer needs to control.

class Bird {
    boolean canFly();
    void teach();
    void fly();
}

try
{
  if(!b.canFly()) { b.teach(); }
  b.fly();
} catch (e) { ... }

Having the perspective, that a method is order dependant upon another method doesn't follow my understanding of OOP design. The object has an internal state. The object manages it's own internal state, and outside source code shouldn't be responsible for management of that state (if possible). If you have to tell the developers to execute the methods in a given order, then you've designed the object wrong.

Instead of teaching and flying. You should initialize the bird, and make handling of the Bird's internal state an internal matter of the object. This way, you will not break other people's source code when you have to revise the design of Bird.

class Bird {
   private boolean taught = false;
   private boolean flying = false;
   private void teach() {...}

   protected void init() {
      if(!this->taught) { this->teach(); }
   }

   public void startFlying() { this->init(); this->flying = true; }
   public void stopFlying() { this->init(); this->flying = false; }
}
2
  • 1
    This is a possible way, but the OP was looking for a pattern that made it obvious to the coder from the external interface that the bird must Learn before it can Fly. That implies that Learn()ing and Fly()ing might have to happen at very different times or even in different threads (Learn() might, in the real world, be a long-running algorithm, and so you don't want it called synchronously, but it must complete at least once prior to Fly()ing).
    – KeithS
    Commented May 8, 2013 at 22:00
  • @KeithS very true. I like some of the above answers better. lol
    – Reactgular
    Commented May 8, 2013 at 22:04
0

My solution sort of bends UML around its corners but I think it's worth a shot. if it's only to make a fellow programmer know how to call the methods, then this may suffice

When you model your design of the Bird class, add a dependence between methods. Currently, UML only allows dependence between objects but you may choose a define a standard which allows you specify dependencies between attributes. This way, the dependence…

fly --------------> learn

…would mean fly depends on learn

In implementation, you may have a flag which indicates the bird has learnt how to fly. if the amount of things to learn becomes too many, you may want to abstract the learnedness of the bird into a different class altogether; thereby falling back to the better part of the pre-stated answers

-1

The accepted answer is not up to OO standards as I understand this solution, because it would imply the object changing class. First we dealt with an instance of Bird, then with an instance of EducatedBird.

This is an anti-pattern requiring you to copy state of the old object to the new, and to check that all references to the "old" object now point to the "new" object.

A State pattern implementation is better: a Bird has an association with Education. This is an abstract class. The actual instance a Bird has a relation with is an instance of a concrete subclass. The Bird instance remains the same throughout its life.

When a Bird is born, its Education is actually an instance of a subclass of Education called, say, "None".

Actually you could delegate the responsibility of "learning" to that class, thereby making Bird simpler (everything related to education is delegated out of the class). So that the Bird will soon become "Novice" and then move on from "Grad" to "Master" and finally "Guru", so it will be able to post on Stack Exchange ;-)

0

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.