3

This is the very first time that I think I want to create a program which really uses OOP principles and I want to do it in the most effective and efficient way.

First of all we are given this (great) riddle :

100 prisoners are imprisoned in solitary cells. Each cell is windowless and soundproof. There's a central living room with one light bulb; the bulb is initially off. No prisoner can see the light bulb from his or her own cell. Each day, the warden picks a prisoner equally at random, and that prisoner visits the central living room; at the end of the day the prisoner is returned to his cell. While in the living room, the prisoner can toggle the bulb if he or she wishes. Also, the prisoner has the option of asserting the claim that all 100 prisoners have been to the living room. If this assertion is false (that is, some prisoners still haven't been to the living room), all 100 prisoners will be shot for their stupidity. However, if it is indeed true, all prisoners are set free and inducted into MENSA, since the world can always use more smart people. Thus, the assertion should only be made if the prisoner is 100% certain of its validity.

Before this whole procedure begins, the prisoners are allowed to get together in the courtyard to discuss a plan. What is the optimal plan they can agree on, so that eventually, someone will make a correct assertion?

So I've got a solution and I want to create a program to run it. I want my program to be as modular as possible, meaning that if I find a better solution, I don't to have to rewrite all of my code. I think OOP is really suited for this.

Here's what I've done so far:

  • A Main class : where I just run several games to test solutions
  • A Game class : which just runs one 'attempt'. It has a 'jail' (which is just an array of prisoners), a day counter and other useful stuffs.
  • And a Prisoner class : which just represent one single prisoner.

After thinking this through, the only things that one prisoner can do are changing the light where they're picked and stating (or not) that everyone has come in the room.

In the solution I've come up with, I have two types on Prisoner. What I've done is that I just implemented my Prisoner class with the most classic type of Prisoner and created a subclass which simply overrides methods from the Prisoner class.

Right now, I see two possible improvements if I want to reuse my code :

  • make the Prisoner class a Java interface, so that when I want to create a new type, I'd just have to implement a Prisoner. But the main issue is that I mostly have 'typical prisoners', a lot of people having the same pattern. Do I just create a implementation 'Classic_Prisoner' ?

  • creating a Behaviour class which handles what behaviour one Prisoner have given a single situation. But isn't just the same problem ? I mean I would also have to create one Behaviour subclass for each type of Prisoner I'm considering.

What to do to have the cleanest code there and be able to reuse it when the time comes?

  • Shouldn't the day counter be in the main class? – JeffO Feb 5 '14 at 10:59
  • Why use inheritance for the prisoners at all? All prisoners are capable of the same actions. There's only one type of prisoner, and unless you change the riddle, there will only ever be one. Likewise, Behavior should be an interface - no need for inheritance at all. – Doval Feb 5 '14 at 12:30
  • 1
    One remark: you should not try to design for reuse (at least, not too early) - you should design for evolvability. Classes will become reusable after you have reused them 3 or 4 times, and refactored them with each iteration. So instead of thinking "I don't want to rewrite all of my code" better think "how can I make later changes to my code as smooth as possible". – Doc Brown Feb 6 '14 at 9:10
  • In which undergraduate year / university questions like this came over? – KcFnMi Jul 17 '16 at 23:11
3

Different "Behaviours" sounds to me like the "strategy" pattern (which inhibits an example for correct use of inheritance or interface usage). This will allow you to change the behaviour of each prisoner easily at run time, which is not easily possible with different Prisoner subclasses.

Besides that, to my understanding of your problem, all Prisoners are equal (at least from the viewpoint of data management and available behaviours), so I don't think inheritance is a good idea for modeling Prisoner objects.

  • I almost said that on my answer and with the comments I was even about to talk about that. +1 for strategy pattern. – Pierre Arlaud Feb 5 '14 at 13:36
  • Thank you for the answer. Another question though : the only attribute that my prisoners have is Behaviour (because that's what make them what they are). Isn't it too much to create a Prisoner class just for it to have a Behaviour ? Obviously, if I ever decide that my prisoners are more that just behaviours, it will be easier to implement this, but nonetheless, I feel that we could get rid of the Prisoner class... – Rivten Feb 5 '14 at 15:37
  • @Rivten: don't you need a counter for each prisoner how often he/she has visited the living room, and what his/her last action was? – Doc Brown Feb 5 '14 at 17:25
  • @DocBrown : The way I see it is the following : there is two sides to take into account : the one that is purely for the riddle and the one which take my solution into account. For the riddle, I just need to know if one prisoner has visited the room. After that, my particular solution can take into account the fact that each prisoner is required to count how many times he has visited. I think (but I'm here to learn) it would be better to separate these views. So in my Game class, I just had a map <Prisoner, boolean> which handles who has already visited. – Rivten Feb 5 '14 at 18:20
  • @Rivten: even if your prisoners have no attributes, you will need to ensure the identity of each prisoner (otherwise you cannot use them as keys in your map). So if your prisoners should be able to change behaviour at run time, you need a separation between prisoners and behaviour. – Doc Brown Feb 5 '14 at 21:40
0

I'll try to give you a quick and efficient answer. I will not help you solve the problem but rather be purely technical about your OOP.

About the Prisonner class being an interface : no. You should consider inheritance. If some prisoners are "like prisoners" but with some new features, make a WithSuchFeaturePrisoner class which you can also store in your jail array thanks to polymorphism.

Behaviour however sounds like a typical interface name. If the behaviour is dependent on the type of prisoner then it belongs to the Prisoner class as a method. Just to give you an idea:

enum Situation {
  A,
  B,
  C
}

interface Behaviour {

  public void whatToDoWhen(Situation happens);

}

class LazyPrisoner implements Behaviour {

  public void whatToDoWhen(Situation happens) {
    // I do nothing
  }

}

I have not thought the entire problem through — and made abstraction of it — because I want to leave you the satisfaction of solving it yourself (and heck, I too am a LazyStackExchangeUser), but I hope this helps.

  • I don't really care about the solution, I've already got one ! What I really want to do well is the design ! So what you say is interesting. I tend to see an interface as something you can't really create but somewhat has button so that you can play with it. The way I see it (and I want you to tell me why I'm wrong !), I've got prisoners with which I want to interact. But each prisoner is different ! To me, an interface is like another level of abstraction. 'What can I do with a prisonner ?' and 'What is this prisoner ?' are different. Isn't that a reason to make it an interface ? – Rivten Feb 5 '14 at 11:40
  • 3
    @Arlaud Inheritance is almost never the right answer. Making a WithSuchFeaturePrisoner and a WithAnotherFeaturePrisoner works until you realize you also need an WithBothFeaturesPrisoner. There's also the fragile base class problem; designing for inheritance requires more thought and care. Composition dodges both problems and is inherently, well...composable. – Doval Feb 5 '14 at 12:23
  • @Doval sortof, inheritance is a good tool. the problem here is that he's trying to inherit based on something the object has, rather than something it is. (ie has-a rather than is-a). For the former its down to properties on the class, for the latter inheritance works well. – gbjbaanb Feb 5 '14 at 13:24
  • @gbjbaanb Has-a vs Is-a is usually a meaningless distinction. Most is-a relationships can be expressed as has-a relationships. A PoisonousSnake that extends Snake can also be expressed as a Snake with poison as its biteType. – Doval Feb 5 '14 at 13:29
  • @Doval Point taken, inheritance makes code static. But it's a solution that should at least be considered. – Pierre Arlaud Feb 5 '14 at 13:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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