views:

869

answers:

5

I have just started to learn Java and is curious is it any good practice in Java for good object decomposition? Let me describe a problem. In big software project it's always a big classes like 'core' or 'ui' that tends to have a lot of methods and are intended as a mediators between smaller classes. For example, if user clicks a button on some window, this window's class sends a message to 'ui' class. This 'ui' class catches this message and acts accordingly by doing something with application user interface ( via calling method of one of it's member objects ) or by posting message to application 'core' if it's something like 'exit application' or 'start network connection'.

Such objects is very hard to break apart since they are a mere mediators between a lots of small application objects. But having a classes in application with hundreds and thousands of methods is not very handy, event if such methods are trivial task delegation from one object to another. C# solves such problem by allowing to break class implementation into multiple source files: you can divide god object any way you choose, and it will work.

Any practices by dividing such objects in Java?

A: 

I've seen some cases where this is solved by inheritance: let's say class Big takes care of 5 different things, and (for various reasons) they all have to be in the same class. So you pick an arbitrary inheritance order, and define:

BigPart1 // all methods dealing with topic #1
BigPart2 extends BigPart1 // all methods dealing with topic #2
...
Big extends BigPart4 // all methods dealing with the last topic.

If you can really layer things up, so that the breakage makes sense (Part2 actually uses stuff from Part1, but not vice versa, etc.) then maybe it makes some sense.

The place where I've seen this is in WebWorks, where a single class had tons of getter/setter methods -- the setters used for dependency injection (e.g., URL args passed to the object upon execution) and the getters for making values accessible to various page templates (I think it was JSPs).

So, the breakdown grouped stuff logically, e.g., assuming the class was called MyAction, there was MyActionBasicArgs (fields and setters for basic CGI arguments), extended by MyActionAdvancedArgs (advanced-option args), extended by MyActionExposedValues (getters), extended by MyActionDependencies (setters used by Spring dependency injection, non-CGI args), extended by MyAction (which contained the actual execute() method).

Because of the way dependency injection in WebWorks works (or at least, used to work, back then), it had to be one huge class, so breaking it down this way made things more maintainable. But first, please, please, see if you can simply avoid having a single huge class; think carefully about your design.

M. Elkstein
unfortunately this is good if program parts are hierarchycally organized. In real life, things a core looks for are "xml parse", "network server", "network client", "user interface", "log facility" etc. It's hard to inherit one delegation group from another in such cases :)
Eye of Hell
I think this is a pretty bad idea. It's too easy for a method in, say, BigPart4 to accidentally override a superclass's method. Interesting idea but it's probably better not to abuse Java's inheritance like this.
Outlaw Programmer
@Eye of Hell I think the idea here is to not use inheritance in the classic sense, but instead to divide methods into logical groups so that the .java files become readable. Client code always has a reference to Big which still contains ALL methods.
Outlaw Programmer
this will prevent one god object methods to call another, and if 'core' is overseer and mediator this will be very common :(. For example, if i move 'network' to a parent class, it will loose ability to call it's child 'xml parser' methods and vice verse :(
Eye of Hell
Really really can't be a good idea. Please don't do this. Containment over Composition whenever you have the choice!
Bill K
BillK: I think you mean composition over inheritance? Outlaw: I'm not necessarily advocating this answer, but you can enable missing @Override annotations to prevent this.
glenviewjeff
+6  A: 

One way to begin breaking such a large object apart is to first find a good subset of fields or properties managed by the large object that are related to each other and that don't interact with other fields or properties of the object. Then, create a new, smaller object using only those fields. That is, move all logic from the large class to the new smaller class. In the original large class, create a delegation method that simply passes the request along. This is a good first step that only involves changing the big object. It doesn't reduce the number of methods, but it can greatly reduce the amount of logic needed in the large class.

After a few rounds of doing this, you can begin to remove some of the delegation by pointing other objects directly at the newer, smaller objects, rather than going through the previously-huge object that was in the middle of everything.

See Wikipedia's Delegation pattern discussion for example.

As a simple example, if you have a personnel object to represent staff at a company, then you could create a payroll object to keep track of payroll-related values, a ratings object to keep track of employee ratings, an awards object to keep track of awards that the person has won, and so on.

To wit, if you started out with one big class containing the following methods, each containing business logic, among many other methods:

...
public boolean isManagement() { ... }
public boolean isExecutive() { ... }
public int getYearsOfService() { ... }
public Date getHireDate() { ... }
public int getDepartment() { ... }
public BigDecimal getBasePay() { ... }
public BigDecimal getStockShares() { ... }
public boolean hasStockSharePlan() { ... }
...

then this big object could, in its constructor, create a newly created object StaffType and a newly created object PayInformation and a newly created object StaffInformation, and initially these methods in the big object would look like:

// Newly added variables, initialized in the constructor (or as appropriate)
private final StaffType      staffType;
private final PayInformation payInformation;
private final PayInformation payInformation;

...

public boolean isManagement() { return staffType.isManagement(); }
public boolean isExecutive() { return staffType.isExecutive(); }
public int getYearsOfService() { return staffInformation.getYearsOfService(); }
public Date getHireDate() { return staffInformation.getHireDate(); }
public int getDepartment() { return staffInformation.getDepartment(); }
public BigDecimal getBasePay() { return payInformation.getBasePay(); }
public BigDecimal getStockShares() { return payInformation.getStockShares(); }
public boolean hasStockSharePlan() { return payInformation.hasStockSharePlan(); }
...

where the full logic that used to be in the big object has been moved to these three new smaller objects. With this change, you can break the big object into smaller parts without having to touch anything that makes use of the big object. However, as you do this over time, you'll find that some clients of the big object may only need access to one of the divisible components. For these clients, instead of them using the big object and delegating to the specific object, they can make direct use of the small object. But even if this refactoring never occurs, you've improved things by separating the business logic of unrelated items into different classes.

Eddie
"In the original large class, create a delegation method that simply passes the request along" <- one method? or methods for each of god object's decomposed functions?
Eye of Hell
@Eye of Hell: I expanded my answer to answer your question.
Eddie
code inside StaffType will have a VERY hard time accessing god object's methods. You will need to dependency inject god object's reference back to staffType. Is it the recommended way for doing such things in Java ?
Eye of Hell
The point is that you do this where the items in StaffType don't need to reference anything outside of what you moved into StaffType. If every field of the god object truly depends on every other field of the object, it's a difficult task to decompose the object.
Eddie
they not like truly depends - they just tends to call it by high-level app logic. For example, if core receives 'main window minimize' message it will access config manager to get settings, try icon manager to optionally show tray icon and a dozen of ui parts managers to hide them
Eye of Hell
A lot of UIs get around the god object antipattern by propagating the event to children. The "main widow minimize" event get set to the icon manager and other ui parts, and then they decide what to do because of the event.
Laplie
A: 

The next logical step may be to change the BigClass into a java package. Next create new objects for each group of related functionality (noting in each class that the object is part of the new package).

The benefits of doing this are dependency reduction and performance.

  1. No need to import the entire package/BigClass just to get a few methods.
  2. Code changes to related functionality don't require a recompile/redeploy of the entire package/BigClass.
  3. Less memory used for allocating/deallocating objects, since you are using smaller classes.
Dana the Sane
and how to address such many-objects-inside-a-package? for example, i break 'core' class into a 'core' package and now it has core.ui.main, core.ui.log etc. And now a log window want to notify core that user clicks 'sort' button. How can it call core.ui.log.sort()? all methods must be static or?
Eye of Hell
You would do: import core.ui.*; then either instantiate log or call the sort() method statically, however you've code things.
Dana the Sane
A: 

Yes, C# provides partial classes. I assume this is what you are referring to when you say:

C# solves such problem by allowing to break class implementation into multiple source files: you can divide god object any way you choose, and it will work.

This does help make huge classes more manageable. However, I find partial classes best used when one needs to extend code created by a code generator. When a class is as large as you're talking about, it can almost always be divided into smaller classes by proper object oriented design. Using a partial class sidesteps the more correct object oriented design, which is sometimes OK as the end goal is stable, reliable, maintainable code, and not a textbook example of OO code. However, many times, putting the code of a large object into a large number of smaller partial class instances of the same class is not the ideal solution.

If you can possibly find subsets of the properties of the "god" object that do not interact with one another, then each one of those sets would logically make a good candidate for a new object type. However, if all properties of this "god" object depend on one another, then there is not much you can do to decompose the object.

Eddie
+1  A: 

I don't know why you would ever have such a large class.

I suppose if you were using a gui builder code generation and being lazy about it, you might end up in such a situation, but codegen usually ends up nasty unless you take control yourself.

Splitting a single class arbitrarily is a terrible solution to a terrible manufactured problem. (Code reuse, for one thing will become virtually impossible)

If you have to use a GUI builder, have it build smaller components, then use the small components to build up a bigger GUI. Each component should do exactly one job and do it well.

Try not to EVER edit generated code if you can avoid it. Putting business logic into a genned "frame" is just a horrid design pattern. Most code generators aren't very helpful with this, so try to just make a single, minimal edit to get at what you need from external classes (think MVC where the genned code is your View and the code you edit should be in your Model and Controller).

Sometimes you can just expose the getComponents method from the Frame object, get all the components out by iterating through the containers and then dynamically bind them to data and code (often binding to the name property works well), I've been able to safely use form editors this way, and all the binding code tends to be very easily abstracted and reused.

If you're not talking about generated code--Well in your "God" class, does it do exactly one small job and do it well? If not, pull out a "Job", put it in it's own class, and delegate to it.

Is your GOD class fully factored? When I've seen huge classes like this, I've usually seen a lot of copy/paste/edit lines. If there is enough of a similarity to copy and past and edit some section, then there is enough to factor these lines into a single chunk of code.

If your big class is a GUI class, consider decorators--reusable and moves stuff out of your main class. A double win.

I guess the answer to your question is that in Java we just use good OO to ensure that the problem doesn't arise in the first place (or we don't--Java's certainly not immune to the problems you are talking about any more than any other language)

Bill K