| View previous topic :: View next topic |
| Author |
Message |
skeftomai Guest
|
Posted: Tue Oct 28, 2008 7:10 pm Post subject: Is this bad design? |
|
|
Hi,
Let's suppose I have a control panel application which allows me to
manage multiple web sites. Each site can have n groups and n members.
Now suppose I have the following classes:
Site
+--getId() : integer
+--getName() : string
Group
+--getId() : integer
+--getName() : string
Member
+--getId() : integer
+--getName() : string
Would it bad design to have a getGroups() method in the Site object,
which returns an array of Group objects representing the groups
associated with the site? Should this getGroups() function go in some
other object?
And likewise, would it be bad design to have a getMembers() function
in the Group object, returning an array of Member objects representing
the members that belong to the group? |
|
| |
|
Back to top |
Patrick May Guest
|
Posted: Wed Oct 29, 2008 4:57 pm Post subject: Re: Is this bad design? |
|
|
skeftomai <chad.d.johnson@gmail.com> writes:
| Quote: | Let's suppose I have a control panel application which allows me to
manage multiple web sites. Each site can have n groups and n members.
Now suppose I have the following classes:
Site
+--getId() : integer
+--getName() : string
Group
+--getId() : integer
+--getName() : string
Member
+--getId() : integer
+--getName() : string
Would it bad design to have a getGroups() method in the Site object,
which returns an array of Group objects representing the groups
associated with the site? Should this getGroups() function go in some
other object?
And likewise, would it be bad design to have a getMembers() function
in the Group object, returning an array of Member objects representing
the members that belong to the group?
|
I would say definitely probably. ;-)
From this description, you're driving your design from a
data-centric point of view. Don't worry about the data structures
initially, focus on the behavior you want from the system. Once you've
defined an implementable subset of the behavior, write some tests to
show it not working. Then write some code to make it work. Then do it
again.
You'll find that the class model that emerges from this process is
almost certainly not the one you came up with initially. In addition,
the interfaces exposed by the classes will have few or no accessors and
mutators (tell, don't ask), but will consist of commands that are
meaningful in your domain.
Regards,
Patrick
------------------------------------------------------------------------
S P Engineering, Inc. | Large scale, mission-critical, distributed OO
| systems design and implementation.
pjm@spe.com | (C++, Java, Common Lisp, Jini, middleware, SOA) |
|
| |
|
Back to top |
H. S. Lahman Guest
|
Posted: Wed Oct 29, 2008 8:17 pm Post subject: Re: Is this bad design? |
|
|
Responding to skeftomai...
| Quote: | Let's suppose I have a control panel application which allows me to
manage multiple web sites. Each site can have n groups and n members.
Now suppose I have the following classes:
Site
+--getId() : integer
+--getName() : string
Group
+--getId() : integer
+--getName() : string
Member
+--getId() : integer
+--getName() : string
Would it bad design to have a getGroups() method in the Site object,
which returns an array of Group objects representing the groups
associated with the site? Should this getGroups() function go in some
other object?
|
Probably. It depends on what getGroups returns.
What you have is:
[Member]
| *
|
| R1
|
| 1 * R 3 ?
[Site] ------------- [Client]
| 1
|
| R2
|
| *
[Group]
You will very likely already have collections for the R1 and R2
associations because they are 1:* relationships. What a Client needs is
access to the R2 collection class so it can "walk" the site members. So
if getGroups returns a handle to that collection class, that is standard
relationship navigation that is orthogonal to the class semantics of
[Site]. The only required semantics for [Site] is that it knows what
associations it has, which is part of its static model definition in OOA/D.
OTOH, if getGroups returns a specific set of [Group] objects as a
<copied> collection, then that is a design no-no. That's because the
getGroups is then a collection responsibility so one is duplicating the
R2 collection management semantics (i.e., it has to know about what's in
the collection and how to access what's in the collection) in the [Site]
definition in addition to its other responsibilities in the problem
solution.
[The key is public responsibility (i.e., what the specification of the
object's responsibilities are with respect to arbitrary clients) and
private implementation semantics. *IF* the Site needs to collaborate
with [Group] objects, it will have to understand those things. But
relationships define connectivity, not collaboration. Client may well be
the only object that needs to collaborate with a Group. In that case
Site needs to know nothing about Groups, other than that there is a 1:*
relationship. So if Site does need to collaborate with a Group, that is
a personal matter between it and [Group] so it should be hidden in its
private implementation, not exposed in its public definition.]
<aside>
There is a potential referential integrity problem because someone might
add/remove elements from the R2 collection while it is being accessed by
Client in a concurrent and/or distributed implementation environment. In
that case the OOP implementation is obligated to ensure that doesn't
happen within the scope of Client's access. From an architectural view
there are several ways to do that. Perhaps the easiest is to provide a
new set of R2 objects that is a copy of the ones in the R2 collection.
Then Client works with its own personal "snapshot".
However, if one does that it should be the R2 collection class that does
the copying. That's because it *is* an architectural decision and
incorporating it in the collection semantics is the most logical and
reusable place to do it. This is one reason why one wants Client to
navigate directly to the R2 collection. Even if the original development
is synchronous and referential integrity isn't a problem, later
maintenance may introduce concurrency or whatever where it becomes a
problem. That maintenance will be a lot easier and less error-prone if
one can always change just the collection classes (e.g., which will
probably be library classes).
Note that this is one reason why the OO paradigm places so much emphasis
on implementing, instantiating, and navigating relationships. It allows
one to separate the concerns of WHO participates in collaborations from
the concerns of WHEN the collaboration should occur. Typically the rules
and policies for those concerns are quite different and may depend on
quite different contexts. When Client navigates *through* Site to get to
Groups for collaboration, one has a mechanism that isolates collection
semantics from the semantics of the collaborating objects -- or any
object along the navigation path.
</aside>
--
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH |
|
| |
|
Back to top |
Daniel T. Guest
|
Posted: Thu Oct 30, 2008 7:59 am Post subject: Re: Is this bad design? |
|
|
skeftomai <chad.d.johnson@gmail.com> wrote:
| Quote: | Let's suppose I have a control panel application which allows me to
manage multiple web sites. Each site can have n groups and n members.
Now suppose I have the following classes:
Site
+--getId() : integer
+--getName() : string
Group
+--getId() : integer
+--getName() : string
Member
+--getId() : integer
+--getName() : string
Would it bad design to have a getGroups() method in the Site object,
which returns an array of Group objects representing the groups
associated with the site? Should this getGroups() function go in some
other object?
|
Sites "have" Groups, but do they use them? If so, then why are Sites'
clients also using them? If not, why do Sites have them?
| Quote: | And likewise, would it be bad design to have a getMembers() function
in the Group object, returning an array of Member objects representing
the members that belong to the group?
|
Would it be bad design for Sites to have a "getMembers()" function that
returns all the Members from all the Groups it contains?
The more important question is, can objects change the state of a Site,
Group or Member without using a method of the class in question? In
other words, can I call getGroups(), then add a Group to the return
value, thus changing the state of the Site? If so, then there is a
problem with your getGroups() method. |
|
| |
|
Back to top |
|