Figuring out OOP principles

  • Thread starter Thread starter Jordan Bowness
  • Start date Start date
J

Jordan Bowness

I'm trying to develop a bunch of classes and want to do it the right
way.

Say I have 5 classes:

City,
Neighborhood,
NeighborhoodCollection,
House,
HouseCollection

The collection classes are strongly typed collections which inherit
System.Collections.CollectionBase

So once I instanciate everything I need, I may use it as follows:

City.NeighborhoodCollection(2).Housecollection(3).value

So here's my question:

I have a sub in the House class which needs to access some property of
the City class. For example, when calling house.GetAverageIncome(), the
sub needs to know which City the house is in. Make sense?

The only way I was able to figure out how to do this was to pass a
reference down to each child object (when sub new() was called in City,
it populated its NeighborhoodCollection members and created a
NeighborhoodCollection.MyParent reference to itself):

dim NeighborhoodToAdd as Neighborhood = new Neighborhood
NeighborhoodToAdd.MyParent = City
City.NeighborhoodCollection.Add(NeighborhoodToAdd)


This got ugly fast. How should I be referencing the properties in a
class' parent?



Thanks!



================
Jordan Bowness
================
 
I know you didn't ask this but why not make a House class that has a City
and a Neighborhood property. The Neighborhood property could hold a value
from an Enum and you could place each house in a Houses collection.
 
Jordan Bowness said:
I'm trying to develop a bunch of classes and want to do it the right
way.

Say I have 5 classes:

City,
Neighborhood,
NeighborhoodCollection,
House,
HouseCollection

The collection classes are strongly typed collections which inherit
System.Collections.CollectionBase

So once I instanciate everything I need, I may use it as follows:

City.NeighborhoodCollection(2).Housecollection(3).value

So here's my question:

I have a sub in the House class which needs to access some property of
the City class. For example, when calling house.GetAverageIncome(), the
sub needs to know which City the house is in. Make sense?

This sounds like a problem, why does a house know about AverageIncome? That
doesnt seem like a function that my house can provide for me, you know? This
causes a dependency between a house and then entire neighborhood. Seems to
me like you should push this functionality up to the neighborhood, and then
to the city. This way, it makes more sense, if it is part of a house, the
only thing that it *should* average is the income of the inhabitances (spell
check).

If up push the functionality back where it belongs, then the rest of your
code will un-f*ck it's self.


HTH,
Jeremy
 
Public Class City
Private mNeighborhoods As NeighborhoodCollection
Private mName As String

Public ReadOnly Property Neighborhoods As NeighborhoodCollection
Get
Return mNeighborhoods
End Get
End Property

Public Property Name As String
Get
Return mName
End Get
Set(ByVal Value As String)
mName = Value
End Sub
End Property

Public Sub New(ByVal CityName As String)
mNeighborhoods = New NeighborhoodCollection
mName = CityName
End Sub
End Class

Public Class Neighborhood
Private mName As String = String.Empty
Private mCity As City

Public Property Name As String
Get
Return mName
End Get
Set(ByVal Value As String)
mName = Value
End Set
End Property

Public ReadOnly Property City As City
Get
Return mCity
End Get
End Property

Public Sub New(ByVal City As City, ByVal NeighborhoodName As String)
mCity = City
Me.Name = NeighborhoodName
End Sub
End Class

Module MainRoutine
Sub Main()
Dim neighborhood As Neighborhood
Dim city As City

city = New City("MyCity")
neighborhood = New Neighborhood(city, "MyNeighborhood")
city.Neighborhoods.Add(city)
End Sub
End Module


' ---------------------------------------------------------------

The above code should give you an idea of what to do, free-hand
code in newsgroup editor so it's buggy :)


Hope it helps


Mythran
 
Why not declare those members Protected Friends

OHM

Jordan said:
I'm trying to develop a bunch of classes and want to do it the right
way.

Say I have 5 classes:

City,
Neighborhood,
NeighborhoodCollection,
House,
HouseCollection

The collection classes are strongly typed collections which inherit
System.Collections.CollectionBase

So once I instanciate everything I need, I may use it as follows:

City.NeighborhoodCollection(2).Housecollection(3).value

So here's my question:

I have a sub in the House class which needs to access some property of
the City class. For example, when calling house.GetAverageIncome(),
the sub needs to know which City the house is in. Make sense?

The only way I was able to figure out how to do this was to pass a
reference down to each child object (when sub new() was called in
City, it populated its NeighborhoodCollection members and created a
NeighborhoodCollection.MyParent reference to itself):

dim NeighborhoodToAdd as Neighborhood = new Neighborhood
NeighborhoodToAdd.MyParent = City
City.NeighborhoodCollection.Add(NeighborhoodToAdd)


This got ugly fast. How should I be referencing the properties in a
class' parent?



Thanks!



================
Jordan Bowness
================

Regards - OHM# OneHandedMan{at}BTInternet{dot}com
 
Forget that !, Just protected will do the trick, then you can use a public
function in the lower classes to get at it.

OHM

Why not declare those members Protected Friends

OHM



Regards - OHM# OneHandedMan{at}BTInternet{dot}com

Regards - OHM# OneHandedMan{at}BTInternet{dot}com
 
You write with such 'fineness' , I assume this is a technical term used in
the Framework ?
your code will un-f*ck it's self.

:-)

Regards - OHM


Jeremy said:
This sounds like a problem, why does a house know about
AverageIncome? That doesnt seem like a function that my house can
provide for me, you know? This causes a dependency between a house
and then entire neighborhood. Seems to me like you should push this
functionality up to the neighborhood, and then to the city. This way,
it makes more sense, if it is part of a house, the only thing that it
*should* average is the income of the inhabitances (spell check).

If up push the functionality back where it belongs, then the rest of
your code will un-f*ck it's self.


HTH,
Jeremy

Regards - OHM# OneHandedMan{at}BTInternet{dot}com
 
One Handed Man said:
Why not declare those members Protected Friends

But does that really fix the problem? It seems to me that the "House" is
doing something that it shouldn't do, that is, why would a house object
return the average income of the neighborhood? Shouldn't it be the otherway
around?

-
Jeremy
 
Jordan,
In addition to the others comments about the location of GetAverageIncome.
This got ugly fast. How should I be referencing the properties in a
class' parent?
I find passing the "parent" object as a parameter to the constructor of the
child object helps prevent things from getting ugly...

Also having a clear idea of which class encapsulates what attributes &
behaviors also helps (the location of the GetAverageIncome method). I would
expect a House to have an Income amount, while a Neighborhood would have
both an Average Income & Total Income amount, based on the houses in that
Neighborhood, while a City has both an Average Income & Total Income amount
based on the Neighborhoods in the city. Note that City would not know about
the houses, as houses are the Neighborhood's responsibility!
dim NeighborhoodToAdd as Neighborhood = new Neighborhood
NeighborhoodToAdd.MyParent = City
City.NeighborhoodCollection.Add(NeighborhoodToAdd)

I would pass City as a parameter to the constructor of Neighborhood, I would
consider making NeighborhoodCollection.Add a factory method.

Something like:

Public Class City

Private Readonly m_name As String
Private Readonly m_neighborhoods As NeighborhoodCollection

Public Sub New(ByVal name As String)
m_name = name
m_neighborhoods = New NeighborhoodCollection(Me)
End Sub

Public Readonly Property Neighborhoods As NeighborhoodCollection
Get
return m_neighborhoods
End Get
End Property

End Class

Public Class NeighborhoodCollection
Inherits CollectionBase

Private Readonly m_city As City

Friend Sub New(ByVal city As City)
m_city = city
End Sub

Public Readonly Property City As City
Get
Return m_city
End Get
End Property

Public Function Add() As Neighborhood
Dim value As New Neighborhood(m_city)
Me.InnerList.Add(value)
Return value
End Function

End Class

Public Class Neighborhood

Private Readonly m_city As City

Friend Sub New(ByVal city As City)
m_city = city
End Sub

Public Readonly Property City As City
Get
Return m_city
End Get
End Property

End Class

Making the constructors Friend, restricts creating the child objects to the
Cities class library

Then you can use it like

Dim myCity As New City("New City")
Dim myNeighborhood As Neighborhood = myCity.Neighborhoods.Add()
Dim myHouse As House = myNeighborhood.Houses.Add()

I would have HouseCollection & House both have Neighborhood "parents", House
could then implement its City property, by delegating to the Neighborhood.

If Neighborhood or House required other parameters to their constructors the
NeighborhoodCollection.Add & HouseCollection.Add methods would have the
respective parameters.

Hope this helps
Jay
 
In my humble opinion, you had it right to begin with (passing a self
reference to the collection member's constructor).

Since House does not logically inherit from Neighborhood and Neighborhood
does not logically inherit from City, I don't see how declaring the member
variable "Protected" will do any good. You could declare the variable as
"Friend" or "Public", but when you share data like this, the functionality
of the class becomes reliant on logic in another class with which it does
not share an inheritance relationship. This is called coupling, and In
general, this indicates BAD OO design. You don't want classes to rely on
one another to "do the right thing". For example, what if the variable is
Nothing? Should I leave it alone or initialize it to a default instance of
an object? You might know the answer to this question, but chances are,
the next person who works with this code won't.

For the Neighborhood and House constructors, pass an instance of the
Collection that houses it. For example, the House Class would look like
this:

Class House
Private m_parentCollection As HouseCollection

Sub New(ByVal parent As HouseCollection, ...other...params...)
m_parentCollection = parent
End Sub
End Class

For the NeighborhoodCollection and HouseCollection constructors, pass an
instance of the City or Neighborhood. For example the
NeighborhoodCollection would look like this:

Class NeighborhoodCollection : Inherits CollectionBase
Private m_parentCity As City

Sub New(ByVal parent As City, ...other...params...)
m_parentCity = parent
End Sub
End Class

In your code, you'll declare the City first and then pass each object down
to the next class in the organizational heirarchy.

Hope that helps!
 
I'm sorry. As soon as I hit send, I realized that I hadn't really answered your question. However, I was afraid that I was going to miss my ride to the airport, so I had to wait to reply.

My first answer is only half an answer. Once you have constructed your "parent aware" objects, you obviously still need to be able to access that information. For your problem, the preferred way to go about doing this in VB.NET would be to use a ReadOnly Property. For example, the House Class from my first response would be modified to look like this:

Class House
Private m_parentCollection As HouseCollection

Sub New(ByVal parent As HouseCollection, ...other...params...)
m_parentCollection = parent
End Sub

Friend ReadOnly Property Parent() As HouseCollection
Get
return m_parentCollection
End Get
End Property
End Class

You may ask, "How is this much different from marking m_parentCollection as Friend?" In this case it is not, except that you cannot assign a value to the property (because it's ReadOnly). For example:

MyHouse.Parent = New HouseCollection(...)

would generate a compile error. The benefit to using a property is that it allows for more flexibility when it comes to future implementation changes/extensibility. Right now, determining a House's parent only involves returning the value of a member variable, but at some point this might require a different set of operations. If you wrap the functionality in a property to begin with, you won't break the class's interface when you change the underlying logic. I marked the property "Friend", because it is probably best to start with a more restrictive access modifier and only move to "Public" if necessary. You probably won't break anything by changing "Friend" to "Public", but the opposite is not true.

Well, I think I've rambled on quite enough. I hope that some of this helps :-) Best of luck with your application!


----- Kevin Halverson [MSFT] wrote: -----

In my humble opinion, you had it right to begin with (passing a self
reference to the collection member's constructor).

Since House does not logically inherit from Neighborhood and Neighborhood
does not logically inherit from City, I don't see how declaring the member
variable "Protected" will do any good. You could declare the variable as
"Friend" or "Public", but when you share data like this, the functionality
of the class becomes reliant on logic in another class with which it does
not share an inheritance relationship. This is called coupling, and In
general, this indicates BAD OO design. You don't want classes to rely on
one another to "do the right thing". For example, what if the variable is
Nothing? Should I leave it alone or initialize it to a default instance of
an object? You might know the answer to this question, but chances are,
the next person who works with this code won't.

For the Neighborhood and House constructors, pass an instance of the
Collection that houses it. For example, the House Class would look like
this:

Class House
Private m_parentCollection As HouseCollection

Sub New(ByVal parent As HouseCollection, ...other...params...)
m_parentCollection = parent
End Sub
End Class

For the NeighborhoodCollection and HouseCollection constructors, pass an
instance of the City or Neighborhood. For example the
NeighborhoodCollection would look like this:

Class NeighborhoodCollection : Inherits CollectionBase
Private m_parentCity As City

Sub New(ByVal parent As City, ...other...params...)
m_parentCity = parent
End Sub
End Class

In your code, you'll declare the City first and then pass each object down
to the next class in the organizational heirarchy.

Hope that helps!
 
Back
Top