tags:

views:

459

answers:

10

Let's say I have one class Foo that has a bunch of logic in it and another class Bar which is essentially the same. However, as Foo and Bar are different (but related) entities I need the difference to be apparent from my code (i.e. I can tell whether an instance is a Foo or a Bar)

As I was whacking this together without much thought I ended up with the following:

public class Foo {
  /* constructors, fields, method, logic and what-not */
}

public class Bar extends Foo {
  /* nothing here but constructors */ 
}

Is this OK? Is it better to make Bar a composite class? e.g:

public class Bar {
  private Foo foo;

  /* constructors and a bunch of wrapper methods that call
     into foo */
}

Or even, while we're at it, something much more low-tech:

public class Foo {
  /* constructors, fields, method, logic and what-not */

  private boolean isABar; // Could be an enum
}

What do you think? How do you deal with these 'marker classes'?


As an example of how my code may wish to treat Foo and Bar differently, my code would need to be able to do stuff like List<Foo> and List<Bar>. A Foo couldn't go in a List<Bar> and vice versa.

+12  A: 

In my opinion, it's best if Foo and Bar subclass off a common ancestor class (maybe AbstractFoo), which has all the functionality. What difference in behaviour should exist between Foo and Bar? Code that difference as an abstract method in AbstractFoo, not by using a if statement in your code.

Example: Rather than this:

if (foo instanceof Bar) {
    // Do Bar-specific things
}

Do this instead:

class Bar extends AbstractFoo {
    public void specialOp() {
        // Do Bar-specific things
    }
}

// ...
foo.specialOp();

The benefit of this approach is that if you need a third class, that's much like Foo but has just a little bit of difference, you don't have to go through all your code and add edit all the if statements. :-)

Chris Jester-Young
So now he has three classes that do the same thing? Why?
SoloBold
SoloBold: Because it's more extensible. If you use "if" statements, you have to edit all of them when you add another class that should also resemble Foo.
Chris Jester-Young
It also puts all the knowledge of foos and bars into the foo and bar classes, thus decreasing the amount of foo/bar-related knowledge that must otherwise be distributed around other classes in the system. But you are right to point it out. As with all OO architecture decisions there are trade-offs
Cheekysoft
Having some other class check the type of an object to see if that object is a Foo or a Bar scatters responsibility around. Responsibility must be focused. Foo and Bar can each do their unique thing. No other class needs to know.
S.Lott
if "it has all the functionality", then it is not Abstract!!!
csmba
Chris: Thanks for updating your answer. That makes a lot of sense.
SoloBold
A: 

Definitely use a boolean property. It's the simplest solution, unless you foresee the Bar class needing to change it's interface later (e.g. override it's methods).

SoloBold
Your answer isn't wrong in the case that you're indicating a property of the object... Without more information in the original question, it's impossible to say whether your option is better or worse than inheritance. Up from me. :P
Chris Mazzola
I agree--can't determine if the answer is right or wrong without more info from OP. If Foo = DomesticShortHairCat and Bar = TabbyDSHCat, then "isTabby" could be treated as an attribute of a DSH Cat, not a separate breed. :-/
James Schek
A: 

Inheritance is best.
With a boolean property, the class must know about the existence of two different types of objects, and this isn't easily extensible to more than two. Moreover, this approach doesn't let you overload functions.
Composition makes you write wrappers for all functions.

Lev
+3  A: 

It all depends on meaning of the Foo and Bar classes. What they represent, and what's their purpose. Please clarify.

I can imagine situations when each of your solutions and proposed solutions is the right one.

phjr
A: 

your data was not clear enough, but based on what I think you need, I am puzzled why you don't simply go with a 4th option:

Class MainStuff;
Class TypeA;
Class TypeB;

No either make TypeA and B inherit from MainStuff, or make MainStuff a data member of TypeA and TypeB. This depends on the meaning of what these 3 classes are.

csmba
+1  A: 

If there is any likelihood that Foo and Bar could someday diverge in implementation, then your question is answered - use inheritance in whatever way seems best.

But if you're absolutely sure that they'll never diverge, then clearly you're looking at something that should be represented by a single class, such as ThingThatIsEitherFooOrBar.

And with that class made, rather than giving it a boolean property like isFoo, it would be much better to take another look at why you need to differentiate Foo from Bar. What is it about Foos that makes you handle them differently than Bars? Figure that out, and make a property that specifies the information that differs. Are Foos bigger? Then make a property for size (even if it's an enum with values "Foo-sized" and "Bar-sized").

That's about as much as one can say without specific examples of what Foo and Bar might be.

fenomas
+2  A: 

Foo and Bar inherit from FooBarImplementation

I'd make a class FooBarImplementation that would implement the common features of Foo and Bar. Foo and Bar would derive from it. But in your code, never ever use the type FooBarImplementation. My Java days are somewhat behind me, but I guess there must be some kind of way to hide FooBarImplementation from the user code (making it protected, or package visible only, depending on your project organization. This way, no user code will mix Foo for a Bar (and vice versa)?

class FooBarImplementation
{
   public void doSomething() { /* etc. */ }
   /* etc. */
}

class Foo inherits FooBarImplementation { /* etc. */ }
class Bar inherits FooBarImplementation { /* etc. */ }

Foo and Bar composed with FooBarImplementation

Another possibility would be to make Foo and Bar forward each of their methods to an internal class (again, FooBarImplementation). This way, there's no way the user code could be Foo and Bar.

class FooBarImplementation
{
   public void doSomething() { /* etc. */ }
   /* etc. */
}

class Foo
{
   private FooBarImplementation fooBarImplementation = new FooBarImplementation() ;

   public void doSomething() { this.fooBarImplementation.doSomething() ; }
   /* etc. */
}


class Bar
{
   private FooBarImplementation fooBarImplementation = new FooBarImplementation() ;

   public void doSomething() { this.fooBarImplementation.doSomething() ; }
   /* etc. */
}

Do NOT make Foo inherits from Bar (or vice versa)

Shoudl Foo inherits from Barn, Foo would be a Bar, as far as the language is concerned. Don't do it, you'll lose the difference between the objects, and this is what you don't want.

Do not use boolean, and whataver type field

This is the worst idea you could come accross. Bjarne Stroustrup warned against this kind of antipattern for C++, and C++ is not all about OOP. So I guess this pattern is even more "anti" for Java... :-)

paercebal
A: 

As others said, it depends, but if you have common functionality between Foo and Bar and the difference in functionality can be expressed as parameters, then I vote for subclasses. This was basically what we were doing in the end of a practical software course.

We should implement a sudoku-game, and in the end, we had an "AbstractPlayfield", which was able to apply an arbitrary set of rules to an arbitrary playfield. This AbstractPlayfield was subclassed by the individual variants we were supposed to implement. Those subclasses set parameters (mostly the rules and the shape of the board) for the abstract playfield and everything worked like a charm. We even ended up with more inheritance in those subclasses, because several of the variants contained the rules "Numbers must be unique in a row" and "Numbers must be unique in a column".
Using that, we were able to finish the work that was estimated for about 2 month in about 3 days :) (And they annoyed us with "Test those tiny attribute-setting classes, because you might have bugs in there! Test them! Test them! We dont care that all important logic is tested!".)

On the other hand, if the class Bar has no special different functionality from Bar, I do not see the point of adding it - at least from the data you give me. It might make sense if you wanted to do some operations based on types and dispatch on type, but I cannot read that from Foo and Bar. In this case, I'd not create Bar, due to YAGNI.

Tetha
+1  A: 

Basically you need to apply the Strategy Pattern.

Martin OConnor
A: 

If there is no behavioral difference between Foo and Bar, then the class name "Foo" is not abstract enough. Identify the common abstraction between Foo and Bar and rename the class accordingly. Then provide a member field in the class to identify instances as "Foo", "Bar", etc. Use an enum if you wish to limit possible values to "Foo" and "Bar".