• Post Reply Bookmark Topic Watch Topic
  • New Topic

Design question about subclassing vs encapsulation.  RSS feed

 
Mike Howles
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello all,

I've been learning Java the last 3 weeks in my free time, I've got a strong background in JavaScript so while "things are kinda the same" they are "kinda different" as well. The syntax came naturally but I am now struggling with different ways of expressing an idea in a design.

I started a simple little project called "barnYard" and did the probably common exercise of creating a class called Animal with a few methods, etc. I then thought, well, an Animal belongs in a Barn, so let's make a barn class that holds an ArrayList of Animals[] etc... And then there are Farmers, etc...

Then in the true spirit of a tinkerer, I thought well, technically, Farmers and Animals are entities that can reside in a structure, so I rewrote things a little bit where I then had two classes, Actor and Structure, where Animal and Farmer extend Actor, and Barn extends Structure.

Now in JavaScript, the syntax is rather lenient where let's say I for whatever reason wanted to have a container/collection/array/WHATEVER of the following:



You get the idea, totally arbitrary objects that may or may not have anything in common. In the above example, doSomething is a method of Farmer (or maybe Actor, whatever).

Is there any similar design concept in Java? I know that all objects are a subclass of the class Object, but if I cast them (if that's even possible) as such in an ArrayList, how would I then know what they used to be without using instanceof or some other bad choice?

Should I think of making a class that encapsulates the arbitrary objects above, with some property that indicates what type of object they are? Something maybe like:



This way, as I construct Capsule objects, I can set a String indicator (or Enum, whatever), indicating what type of Object is really contained. I could then express some logic in execution such as:



This seems like a roundabout way of accomplishing something that seems very easy in JavaScript. I realize they are two different languages, but they have similar roots. Any insight that anyone has would be appreciated.
 
Jelle Klap
Bartender
Posts: 1952
7
Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You could take a look at the Visitor pattern and see if that's a viable solution.
 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Mike,

Welcome to JavaRanch!

Your Capsule class doesn't buy you anything except unneeded complexity. If you actually had a collection with heterogeneous objects in it, then it would be better to just use the language naturally, like



Where it says "(Actor)", that's called a cast; it's necessary to tell the compiler that an Object is really an Actor before it will let you call a method from the Actor class. In Javascript, you get missing method errors at runtime, but in Java, you get them at compile time.

Now, I said if, because it's exceedingly rare that you'd make a collection in Java and then fill it with completely random, unrelated objects, about which you know nothing. Furthermore, you can often use polymorphism to avoid those casts and instanceofs (have you read about that yet?)

Imagine that Barn, Farmer, Animal, Actor, and Structure are all part of a video game. Then you've probably got an abstract base class called GameObject; Actor and Structure are abstract subclasses of GameObject, and Farmer and Barn are concrete subclasses of Actor and Structure, respectively. In the GameObject class, you'd put all the methods that have to do with being a physical object: having a position, mass, mesh, texture, whatever. You would probably also add abstract methods that react to various events. For example there might be an "abstract void hit(int hp)" method that represented a GameObject being hit. Then Barn and Farmer and the other concrete classes would all implement it. Barn might do nothing; Farmer might bleed or die (what kind of crazy game is this, anyway!) But then you might have a collection of GameObjects



I can call hit() on objects.get(2) because objects is of type List<GameObject>. hit() does the right thing no matter what kind of GameObject you call it on, automatically.

Does this make sense?
 
Mike Howles
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ernest Friedman-Hill wrote:Lots of good stuff

Thanks for your reply. Yes, I've read about polymorphism, and unless I'm mistaken, since I had a base class Actor, and Animal, Farmer extended that, I can then override whatever functions, etc and that is what inheritance/polymorphism is basically about. You filled in the puzzle piece I had by expressing GameObject as the overall class, which would then allow me to template the ArrayList as that object. While I wouldn't call my little project that I'm using to learn Java a game, it more or less is, since I gave Actor hitpoints, etc . Here's another question though. In your example:



Let's suppose that the inheritance is:
GameObject
-Actor
--Farmer
--Animal
-Structure
--Barn

Let's say that Actor implements a new function called hit() which is not present in GameObject. My assumption is that this works fine for Animal and Farmer, but would your example code even work since the hit() is no longer a function of Game Object? I'm assuming even if GameObject does not always hit things, (e.g. Barn cannot hit things, it's a Structure), it still should have an empty hit function?

EDIT: I missed your line about abstract void hit(int hp), this would be in the GameObject class implementation, I'm assuming? I'll have to read up on abstract because I'm unsure what that modifier does, but I think I get the idea.
 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I put hit() in GameObject assuming that any object could be hit. If only Actors can be hit, then there are two possibilities: either you have to do the instanceof test and cast that I showed at first (which is not ideal, but neither is it terrible; oftentimes it's jut what you have to do) or you would consider keeping Actors and Structures in separate lists. There's not a hard and fast rule, but if you find that you're doing a lot of instanceof-checking, then you've probably got a collection that's too generic, and the fix is to use multiple more-specific collections.

An "abstract" method is one that subclasses are forced to implement, but the declaring class doesn't actually implement. It would be like adding an empty variable "hit" to a Javascript prototype; although the name would then be defined for all objects that use that prototype, it won't actually be usable unless the objects that use that prototype give it a value.

An abstract class is one that can only serve as a parent class and can't itself be instantiated (often because it has one or more abstract methods.)
 
Consider Paul's rocket mass heater.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!