Link to home
Start Free TrialLog in
Avatar of dddexter
dddexter

asked on

comparing mutable composite objects (design pattern question)

this must be an already-solved problem.  probably a pattern.

suppose you have a class that is built as a composite (not through
inheritance), that is mutable and whose composite members are
mutable.  e.g.:

public class House {
  private Roof roof;
  private Address address;
  private Set rooms;
...

  public Roof getRoof() { return roof: }  // or a defensive copy of it...
  public void setRoof(Roof r) { roof = r; }  // or a defensive copy of it...
...
}

In what manner can/should instances of House be compared?

1) should equals() and hashCode() be provided?  should equals()
return true only if each recursive equals() returns true down to whatever
level all fields become immutable?

2) should a different method, say hasEqualValues() be provided in
place of equals() so as not to break any HashSet into which a House
has been placed and then mutated?

3) it would seem reasonable to provide a method:
public boolean isSameHouse(House otherHouse) that would return true
if i've only, say, replaced a broken window or painted a room.  How should
such a method be implemented?  should it be implemented?

4) suppose i wish to compare two houses to find where they differ.  i would
be interested in finding, e.g. that a door has been removed between two rooms.
would a method signature such as:
public Set getDifferences(House otherHouse)
fit the bill?  what gets placed in the return Set?  a Door object? how does the
client determine which Door it was?  should the return type be a Map instead
(from the Door object in thisHouse to the Door object in thatHouse)?

5) should the api provide just the equals() (or, hasEqualValues()) at each level
and leave it to the client to worry about how differences are handled?

thoughts?  it's been bugging me for some time....

thanks,

-don.
Avatar of Mick Barry
Mick Barry
Flag of Australia image

When two house objects are considered equal is really a design decision that you need to make. And implement an equals accordingly.
If you have additional comparison techniques you wish to use then you'll need to implement these as seperate methods.
ASKER CERTIFIED SOLUTION
Avatar of Ovi
Ovi

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of iartmirko
iartmirko

Don,

1. I would provide a equals() method for your house. This is a common Java method for comparing two objects. It should return true, if all fields of your houses are equal. That means that the fields that are not primitive should call there equal() methods recursively.

2. If you want to know if two houses are the same instances, just use the == operator. Use equals() only for comparing at field level.

3. Yes, you could define a method called equalsIgnoreReplacements() to define such a method...but it will be difficult to know, because the only stable attribute should be the address...but even that maybe changed...so how do you know that a house is the same whith changed attributes and not different house...you could keep a history for that...

4. I would't neither return a Set nor a HashMap. I would return a House object that contains only those fields that are different and all equal field set to null...

5. I would say that it depends on what you want to do. Think about sorting houses, where you provide a method like public int compare(House ) that return 0 if it is equal, -1 if it is less and >0 if it is greater than the house on which the method is called. Then you will need the house to handle this functionality...

Hope this helped you a little bit.

Mirko
Avatar of dddexter

ASKER

ok, since this seems to be all the discussion the question is going to
genererate on the first go-round, i suppose it's time for a response and
additional comments from me.

objects:
yes, i'm aware that i have to design the classes.  my question was "are
there any design patterns for this?" or, alternatively, "what are some
design suggestions?"  

Ovi:
i've been reading the site you mention and it is indeed full of good
advice and patterns.  the visitor pattern may be something like
what i'm after, but i'm still new to thinking in pattern terms...
your line: "The job of that house is only to provide to the interogator
all information he needs. "  is true.  taken at face value, it implies
that the client (or an interogator object) needs to do all the work.
any further thoughts as to how?

iartmirko:
i'm still not fully convinced about adding an equals().  to do so on
an immutable object is certainly a good idea, but mutable objects
yield other concerns (getting things out of hashSets).  (also, though it
isn't particularly difficult, you *must* implement hashValue() when
overriding equals()).  your point #3 is getting toward the heart of the
matter.

all:
suppose you have a GUI in which you can display houses.  in addition
to the obvious functionality of rotating them and the like, the GUI can
also add rooms, move walls, change doors, etc.   over time, a set of
plans would accumulate.  it may be desireable to ensure that no two
identical sets of plans can be saved.  it may be desireable to pull up
a house and display it "vs. another house"...a wall has been removed,
so a faint red wall is shown, a window added is also shown in red.  etc.
the client is (obviously) doing the display, but who is finding those
differences?  how?

thoughts?

-don.
> it may be desireable to ensure that no two
> identical sets of plans can be saved.

If this is desirable then you should be overriding equals to define what an 'identical' plan is.
I believe you are really try to create a house manipulation GUI. That's not a easy job and require a carefull design. Beginning with the top, I will create such thing splitting as much as possible the GUI from the logic and the model. First of all I would think on how to implement the basic functionalities of a HouseDesigner. I usually use the MVC pattern (Model-View-Controller) and for your case should look like this :

The model :
    - should use AbstractHouse - abstract class defining general house properties.
    - AbstractHouseFactory - factory for creating a specific kind of house, using Factory Method or Abstract Factory patterns.By specific kind I understand predefined type, or already saved type of houses.
    - HouseDesignerModel - a class which represent the model of a drawed house. Should provide methods for querying the global state of a house (visual state stored by this model and house state, stored by a AbstractHouse derivated object).

The controller : can be embed in the same class as the view (following swing MVC concept) or separate. Anyway you should keep in mind that a controller is associated to a specific view.
    - HouseDesignerController - a class which caries the logic of user interaction with the dispolayed oject in the associated view. Should communicate to the model any change of state.

The View :
    - HouseDesignerView - a observer class used to represent the visual state of a house. It should be maded as Observer of the model, and should have a Controller class registered.

So you have solved in the design terms the problem of display/manipulation of a house. The used MVC pattern give you the possibillity to have AT LEAST ONE view associated with the model, so you can virtualy represent a model content in a infinity of synchronized views.

About the GUI this should be simple like a window, a menubar, perhaps a popup menu. For this GUI to be easy to maintain (today you want 3 things to be implemented, tomorrow you will want another new 10), I suggest you to really take into consideration a plugin enabled framework. The plugins would query the basic GUI that you provide for ading menu options for example, or the HouseDesigner component holded by the GUI, and do the necesary things by querying the model of it...

About your last question, thinking in plugin terms, the queries for a allready existant saved planes collection could be impleented in a special save plugin. or a plugin which does the comparation of a saved house properties file (XML like) to a on fly generated one for the editing house.
sorry...
i didn't intend to be taken literally about the house designer gui.
i agree, such a task would be extensive.  i was providing it as an
example only to demonstrate the manner in which these object
comparisons needed to take place.  the actual project i'm working
on (though it does involve a gui) doesn't even involve houses.  all
of that was for illustration purposes only - to give us a framework
for our conversation.

if we're to recast the conversation to MVC terms, i have the model
(the house class that stores all the info...the house "state"), the
controller/view (they are wrapped up in one package, called, for
our purposes, HouseGUI).  the question would then be "does the
comparision functionality belong in 1) the House class (model),
2) the HouseGUI class (view or controller), or 3) somewhere else?"

-don.
sorry...
i didn't intend to be taken literally about the house designer gui.
i agree, such a task would be extensive.  i was providing it as an
example only to demonstrate the manner in which these object
comparisons needed to take place.  the actual project i'm working
on (though it does involve a gui) doesn't even involve houses.  all
of that was for illustration purposes only - to give us a framework
for our conversation.

if we're to recast the conversation to MVC terms, i have the model
(the house class that stores all the info...the house "state"), the
controller/view (they are wrapped up in one package, called, for
our purposes, HouseGUI).  the question would then be "does the
comparision functionality belong in 1) the House class (model),
2) the HouseGUI class (view or controller), or 3) somewhere else?"

-don.
Comment
From: objects  Date: 04/19/2002 04:04PM PST  

> it may be desireable to ensure that no two
> identical sets of plans can be saved.

If this is desirable then you should be overriding equals to define what an 'identical' plan is.
 
This is analagous to how the String class equals works.
In my opinion point 3. The responsability of comparisation should go somwhere else, in a Comparator object. I use equals only for primitive classes (nonmutable).
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:
Answered by: objects
Please leave any comments here within the next seven days.
 
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
 
Venci75
EE Cleanup Volunteer
never did really solve the problem as stated - ended up
deciding that two _different_ houses can't be compared, you
can only compare one house to itself for changes made.  instead of actually performing the comparison, i simply log all changes as they happen and can therefore go back and forth (graphically) through a change log.

i suspect that recasting the problem is the proper answer and that comparisons of the sort i was after don't make much sense.

thanks all,

-don.