Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have a set of base characteristics, and then a number of sub-types. Each instance must be one of the sub-types, but can be multiple sub-types at once. The sub-types of each thing can change. In general, I don't care what subtype I have, but sometimes I do care.

This is much like a Users-Roles sort of relationship where a User having a particular Role gives the user additional characteristics. Sort of like duck-typing (ie. If my Foo has a Bar, I can treat it like a ThingWithABar.)

Straight inheritance doesn't work, since that doesn't allow mix/match of sub-types. (ie. no multi-inheritance).

Straight composition doesn't work because I can't switch that up at runtime.

How can I model this?

share|improve this question
add comment

3 Answers

What you want are Interfaces.

Each interface can mandate a characteristic. A class can implement multiple interfaces as it pleases:

interface Foo {
  boolean doFoo();
}

interface Bar {
  boolean doBar();
}

class fooImpl implements Foo {
  boolean doFoo(){
    . . .
  }

}

class barImpl implements Bar {
  boolean doBar(){
    . . .
  }

}

class fooBarImpl implements Foo, Bar {
  boolean doFoo(){
    . . .
  }
  boolean doBar(){
    . . .
  }
}

UPDATE

Alternatively, implement the state pattern. One state would be HasABar, and would provide the desired behavior for when your Foo has a Bar. Another state might be HasABat, providing different behavior. Your Foo object may start with HasNothing, until you give it a Bar, which would change the state to HasABar.

interface FooState {
   Drink getDrink() throws InvalidStateException;
}

class HasNothing implements FooState {
   Foo foo;

   HasNothing(Foo foo) {
      this.foo = foo;
   }   

   Drink getDrink() throws InvalidStateException {
      throw new InvalidStateException("There's no Bar");
   }
}

class HasABar implements FooState {
   Foo foo;

   HasABar(Foo foo) {
      this.foo = foo;
   }   
   Drink getDrink() throws InvalidStateException{
      Foo foo.getBar().getDrink();
   }
}

class Foo {
   FooState state;
   Bar bar;

   public Foo() {
      state = new HasNothing(this);
  }

   Bar getBar() {
      return bar;
   }

   void setBar(Bar bar) {
      this.Bar = bar;
      if (null != bar) {
         state = new HasABar(this);
      }
      else {
         state = new HasNothing(this);
      }
   }

   Drink getDrink() throws InvalidStateException{
         return state.getDrink();
   }
}

At this point you are not really dealing with subtypes, you've got one type that behaves differently depending on state during runtime.

share|improve this answer
    
No, I'm not looking for Interfaces because those are locked in at compile time and I need something that can change at runtime as my parent Foo changes from being a Bar to a Baz. Also, Interfaces require each concrete class to implement functionality/data-structure, which is the opposite of what I want. –  cdeszaq Apr 3 '12 at 15:53
    
The update seems much more along the lines of what I'm after. But it would require that Foo know all of the possible "behaviors" (or States), which seems a bit inverted. However, it is much closer to what I'm after than plain Interfaces. –  cdeszaq Apr 3 '12 at 17:20
    
It doesn't really need to know the behaviors as such--just that there's something that it might want to do if it was in a certain state. The states might also support differing behavior for other activites as well: relax() could return "Just chillin'" for the HasNothing state and "Chillin' by the bar" for the HasABar state. The interface is defined by foo, but the behavior is defined by the state. –  Matthew Flynn Apr 3 '12 at 18:44
add comment

Start with your main class, User. Then have it contain a list of objects, call them Role instances or implementations. Your Role's all have to look alike to the User so it can talk to them, but their implementations can be very different. (And in fact they can have powers (methods) the User knows nothing about. Each just has to be Role, whatever else might be.) Essentially, when the User is told to do something that it cannot do itself, directly, it will go through the list asking each Role if it can do it. When it finds one that can, it calls that Role's doIt method. And you can swap Role instances in and out of the User at any time.

The User might want to pass a Role instance back to a caller, because the caller might know that a Role with an ID of 6 implements the DatabaseReader interface and has methods the User object knows nothing about.

I'm not sure exactly what you need, but hopefully this will give you some ideas, even if it doesn't solve your problem.

share|improve this answer
    
Yes, this is definitely along the lines of what I'm looking for. How would I go about asking each Role if they can doIt? –  cdeszaq Apr 3 '12 at 17:17
    
@cdeszaq: Ideally each role has a doIt method that does the job that role does in the way that role is supposed to do it. Each different Role instance can have a different method. Alternatively, the role--or something provided by the role--can be passed back to whatever called the User. The caller may know a lot more about the Role or the information or contacts it provides than the User does. –  RalphChapin Apr 3 '12 at 17:29
    
So almost like a template method pattern. That makes sense. Thanks! –  cdeszaq Apr 3 '12 at 17:30
add comment

One way to do this is to a mapping table in a database to map users to allowed permissions, and create a db function to check permissions and add that to the beginning of any db request that requires permissions. This allows run time editing of roles and arbitrary permissions for each user.

share|improve this answer
    
Right, that's the most basic level of it, but the issue is when each "role" gives the "user" object (in code) additional fields and methods. The "extra stuff" for each role is what I'm trying to get. Plain vanilla Roles are easy. –  cdeszaq Apr 2 '12 at 20:57
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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