BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

How to resolve mutual class dependencies
Goto page 1, 2, 3, 4  Next
 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design
View previous topic :: View next topic  
Author Message
Roman Kaßebaum
Guest





PostPosted: Wed Dec 29, 2004 2:38 pm    Post subject: How to resolve mutual class dependencies Reply with quote



Hi,

in another thread Joanna Carter told me to discuss this problem here:

I use an oo framework which has two main tasks: Business rules and
navigation.

Let's see an example: Two entitys company and person, a company has n
persons, a person must have a company.
I have three units, CustomCompany and CustomPerson for business rules.

The third unit is generated. There the classes TCompany derived from
TCustomCompany and TPerson derived from TCustomPerson are implemented.

For navigation a Person has the property Company: TCompany and a Company
has the property PersonList: TPersonList. This means that the classes
TCompany and TPerson(List) must be implemented in the same unit.

The generated unit will grow with the numbers of entitys.

Joanna told:

Quote:
Possible Solutions :

You may need to think of a Role class that acts as intermediary
between the
Company and the Person.

Has someone an idea how such a role class can work?

--
Roman

Back to top
Bob Dawson
Guest





PostPosted: Wed Dec 29, 2004 3:10 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote



"Roman Kaßebaum" wrote
Quote:

Has someone an idea how such a role class can work?

Rather than thinking of a person having an employer and vice versa, think of
a class

TEmploymentContract = class
FCompany : TCompany;
FEmployee : TPerson;
FHireDate : TDateTime;
FDepartureDate : TDateTime;
FDepartureReason : TDepartureReason;
etc;

Now rather than owned lists of employees etc., there is an employment ledger
object. This is a collection manager object capable of holding various
collections of employee contracts.
If needed, the emplyment ledger object is subclassed as TEmployeeRecords
(which adds appropriate methods for dealing with the employees of a company)
and TEmploymentHistory (which adds methods for dealing with the collection
from the employees' point of view).

bobD



Back to top
Peter Morris [Air Softwar
Guest





PostPosted: Wed Dec 29, 2004 9:22 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote



Quote:
You may need to think of a Role class that acts as intermediary
between the
Company and the Person.

This may work for your particular situation, but it wont for them all.

For example, you may have the two classes joined via some kind of abstract
linking class
http://www.howtodothings.com/showarticle.asp?article=713
(It is written for Bold, but it illustrates the point).

However, when you have a house / street situation you definately need a
direct association between the two. There is no "role" here at all, they
are simply linked. This means that eventually you will come across
situations where the classes need to be in the same file.

If you don't like having all of your classes inside a single file (even
though they must be in a single unit), why not try something like this.....

==============================
unit MyClasses;

interface
uses
etc;

type
TPerson = class;
TCompany = class;

TPerson = class(etc)
etc...
end;

TCompany = class(etc)
etc...
end;

implementation

{$I Person.inc}
{$I Company.inc}

end.
==============================

This way at least you can have the implementation code separate. I can see
that not everyone will like this suggestion, but if you really don't want a
single file, but really *must* have a single unit, I can see no other
solution other than making your model over complicated with abstract classes
just to work around the fact that the Delphi compiler is a single-pass
compiler.


--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
http://www.droopyeyes.com

Read or write articles on just about anything
http://www.HowToDoThings.com

My blog
http://blogs.slcdug.org/petermorris/




Back to top
Wayne Niddery [TeamB]
Guest





PostPosted: Thu Dec 30, 2004 3:15 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote

Peter Morris [Air Software Ltd] wrote:
Quote:

However, when you have a house / street situation you definately need
a direct association between the two. There is no "role" here at
all, they are simply linked. This means that eventually you will
come across situations where the classes need to be in the same file.

If you don't like having all of your classes inside a single file
(even though they must be in a single unit), why not try something
like this.....
{$I Person.inc}
{$I Company.inc}

Yuck! :)

The other solution of course is to use interfaces. The interface definitions
will need to be in a common unit, but the class implementations can then be
in separate units, neither needing the other, but only the common interface
unit.

--
Wayne Niddery - Logic Fundamentals, Inc. (www.logicfundamentals.com)
RADBooks: http://www.logicfundamentals.com/RADBooks.html
Bandwagons are like streetcars, there'll be another along in a few
minutes.



Back to top
Peter Morris [Air Softwar
Guest





PostPosted: Thu Dec 30, 2004 5:50 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote

Quote:
{$I Person.inc}
{$I Company.inc}

Yuck! Smile

:-)


Quote:
The other solution of course is to use interfaces. The interface
definitions will need to be in a common unit, but the class
implementations can then be in separate units, neither needing the other,
but only the common interface unit.

Well, that's just deferring the problem to a different unit. Although the
other "everything.pas" unit will at least be smaller due to the fact that it
has no implementation.

Personally I think it is time that the Delphi pascal compiler became two
pass.


--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
http://www.droopyeyes.com

Read or write articles on just about anything
http://www.HowToDoThings.com

My blog
http://blogs.slcdug.org/petermorris/



Back to top
Wayne Niddery [TeamB]
Guest





PostPosted: Thu Dec 30, 2004 7:53 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote

Peter Morris [Air Software Ltd] wrote:
Quote:

Well, that's just deferring the problem to a different unit.

Is it? The issue (I think) is coupling between classes. I.e. it goes beyond
simply the circular unit problem to being a class design issue. Naturally
you don't want all classes defined in a single unit, but if you find
yourself in that situation then maybe there is a coupling problem.

Now you might argue that using interfaces in this situation simply defers
the coupling issue to the interfaces, but I don't think that's a problem.
The problem is coupling between *implementations*, not interfaces.

--
Wayne Niddery - Logic Fundamentals, Inc. (www.logicfundamentals.com)
RADBooks: http://www.logicfundamentals.com/RADBooks.html
“It is error alone which needs the support of government. Truth can
stand by itself.” - Thomas Jefferson



Back to top
Bob Dawson
Guest





PostPosted: Thu Dec 30, 2004 9:40 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote

"Wayne Niddery [TeamB]" wrote
Quote:

Is it? The issue (I think) is coupling between classes. I.e. it goes
beyond simply the circular unit problem to being a class design issue.

it's always a design issue ... <vbg>

Quote:
The problem is coupling between *implementations*, not interfaces.

I don't know--that's a bit easy. Shouldn't it be possible to use the Company
class in a program that doesn't need any employee concept at all? Either as
a dragged-in linked class or a dangling interface?

bobD



Back to top
Peter Morris [Air Softwar
Guest





PostPosted: Fri Dec 31, 2004 11:53 am    Post subject: Re: How to resolve mutual class dependencies Reply with quote

Quote:
Is it? The issue (I think) is coupling between classes.

He stated that his issue was not wanting to have all of his classes inside a
single PAS file. So using interfaces simply defers the issue to a different
unit, MyInterfaces.pas

Quote:
Now you might argue that using interfaces in this situation simply defers
the coupling issue to the interfaces, but I don't think that's a problem.
The problem is coupling between *implementations*, not interfaces.

How you abstract items away depends on your design. For example, a
PurchaseOrder makes no sense without a PurchaseOrderLine. Whereas you *may*
wish to have a company to whom you sell products, and have no need to record
the company's employees.


--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
http://www.droopyeyes.com

Read or write articles on just about anything
http://www.HowToDoThings.com

My blog
http://blogs.slcdug.org/petermorris/



Back to top
Bob Dawson
Guest





PostPosted: Fri Dec 31, 2004 2:34 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote

"Peter Morris [Air Software Ltd]" wrote

Quote:
How you abstract items away depends on your design. For example, a
PurchaseOrder makes no sense without a PurchaseOrderLine.

Not sure about that--I can imagine a system that processes POs for payment
based entirely on PO-level information, and not having any interest in the
line details. And from the shop floor perspective, the order line may
constitute a work requirement without regard to the order it belongs to.

bobD



Back to top
Peter Morris [Air Softwar
Guest





PostPosted: Fri Dec 31, 2004 7:13 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote

Quote:
Not sure about that--I can imagine a system that processes POs for payment
based entirely on PO-level information, and not having any interest in the
line details. And from the shop floor perspective, the order line may
constitute a work requirement without regard to the order it belongs to.

That's confusing two things. You are talking about "different roles
operating on different parts of a composite object" whereas I thought we
were talking about "classes which may exist without each other".


--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
http://www.droopyeyes.com

Read or write articles on just about anything
http://www.HowToDoThings.com

My blog
http://blogs.slcdug.org/petermorris/



Back to top
Bob Dawson
Guest





PostPosted: Sat Jan 01, 2005 12:22 am    Post subject: Re: How to resolve mutual class dependencies Reply with quote

"Peter Morris wrote
Quote:

That's confusing two things. You are talking about "different roles
operating on different parts of a composite object" whereas I thought we
were talking about "classes which may exist without each other".

From my perspective, I'm talking about an object model that's modular enough
to be shared across multiple applications, so common objects can be used
without dragging in a raft of associated classes into applications where
they're not actually required. That means classes that may exist without
each other.

The question is one of which is more important, the ability to navagate
aLineItem := aOrder.LineItems[12]
or the flexibility of keeping Orders and LineItems completely uncoupled, and
having a relational object that can manage their interrelationship when
actually needed:
aLineItemManager := LineItemManager.CreateForOrder(aOrder.ID);
aLineItem := aLineItemManager.Items[12];

I agree that if only one application is ever going to use the objects, then
the first model presents an easier programming paradigm.

bobD



Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Sat Jan 01, 2005 11:42 am    Post subject: Re: How to resolve mutual class dependencies Reply with quote

"Bob Dawson" <RBDawson (AT) prodigy (DOT) net> a écrit dans le message de news:
41d5ed66$1 (AT) newsgroups (DOT) borland.com...

Quote:
The question is one of which is more important, the ability to navagate
aLineItem := aOrder.LineItems[12]
or the flexibility of keeping Orders and LineItems completely uncoupled,
and
having a relational object that can manage their interrelationship when
actually needed:
aLineItemManager := LineItemManager.CreateForOrder(aOrder.ID);
aLineItem := aLineItemManager.Items[12];

When it comes to a composition class like an Order, you *usually* want to
keep any line related functionality totally within the Order class.

Therefore, I would tend to try and use a method like Order.GetItem(12)
simply for the inference that I am asking the Order for one of its lines
rather than the indexed property syntax which, to me at least, implies that
I can get at the Lines as an entity and then get at an individual line from
the Line collection rather than the Order.

This is one of the occasions where I feel that using RTTI on published
properties in a RAD environment has coloured our design thinking.

<ramble>
I am embarking on rewriting my VTF (Value Type Framework), OPF and MVP in C#
for .NET and it has caused me to think very carefully about the best method
of providing sufficient metadata for storage and UI purposes.

One argument that seems to have solidified itself is that I will use
'fields' as the source of data for streaming as they should represent the
*state* of the object better than properties which can be virtual, read-only
or even non-existent.

Now having said that I will use fields, I am also looking at the idea that
any class can be serialized in that I can iterate through the fields
(omitting those marked with the non-serializable attribute; or that
serialization can *also* occur on instances of any class that supports
ISerializable. In the latter case, I can use the VTF to supply the values
for streaming to a SerializationInfo object that is required by the
GetObjectData method of ISerializable.

In fact, using a SerializationInfo object could completely remove the need
for the VTF ??
</ramble>

Anyway, to tie back in to the theme of your post, if we use 'inner' values
rather than properties for state of objects then we don't need to surface a
Lines property on an Order class because the OPF/UI can get at the objects
using reflection or the like, whilst maintaining a 'tighter, cleaner'
interface to the business logic side of things.

My main concern is that 'navigability', polluted by RAD thinking is
influencing OO design for the worse. In my experience, navigation as implied
by indexed properties is usually convenient for RAD UI work; row 0 in the
grid requires item 0 in the list, etc. Well written UI adapter classes
should be able to deal with this kind of situation; after all a TDataset
acts as an Adapter between a unidirectional SQL cursor and a bi-directional
grid.

Starting the new year with a good argu^H^H^H^H discussion Smile)

Happy New year to all

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker



Back to top
Peter Morris [Air Softwar
Guest





PostPosted: Sat Jan 01, 2005 12:48 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote

Quote:
From my perspective, I'm talking about an object model that's modular
enough
to be shared across multiple applications, so common objects can be used
without dragging in a raft of associated classes into applications where
they're not actually required. That means classes that may exist without
each other.

In the case of a Customer / PurchaseOrder relationship I agree, a customer
may not always have purchase orders. However, when it comes to
PurchaseOrder/OrderLines I believe that a PO will *always* have lines. Just
because your invoicing service only ever reads the header, and your stock
service only ever reads the lines, doesn't mean that they are separate, they
are mutually dependent.


--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
http://www.droopyeyes.com

Read or write articles on just about anything
http://www.HowToDoThings.com

My blog
http://blogs.slcdug.org/petermorris/



Back to top
Jim Cooper
Guest





PostPosted: Sat Jan 01, 2005 1:27 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote


Quote:
Therefore, I would tend to try and use a method like Order.GetItem(12)

Hmmm. I always feel quite uncomfortable when I end up naming methods
"Get...". I always feel that it should be a property Smile I don't have a
problem with indexed properties - they can be very nice.

I'm not sure I agree that they are particularly a RAD thing

Cheers,
Jim Cooper

_______________________________________________

Jim Cooper [email]jim (AT) falafelsoft (DOT) com[/email]
Falafel Software http://www.falafelsoft.com
_______________________________________________

Back to top
Bob Dawson
Guest





PostPosted: Sat Jan 01, 2005 4:22 pm    Post subject: Re: How to resolve mutual class dependencies Reply with quote

"Joanna Carter (TeamB)" wrote
Quote:

When it comes to a composition class like an Order, you *usually* want
to keep any line related functionality totally within the Order class.

Why shouldn't such functionality belong to the OrderLines collection? And
why shouldn't using this class be optional at the program (model
utilization) level, rather than being inherent to the Order object?

Quote:
rather than the indexed property syntax which, to me at least, implies
that
I can get at the Lines as an entity and then get at an individual line
from
the Line collection rather than the Order.

I don't see any reason that the OrderLine collection has to be dumb--so why
shouldn't you? Why not
aLine := OrderLines.NewLine;
or why not
NbrOfItems := OrderLines.Count;
rather than
NbrOfItems := Order.OrderLineCount;

Quote:
This is one of the occasions where I feel that using RTTI on published
properties in a RAD environment has coloured our design thinking.

Never did that in my BO design. :-)

Quote:
In fact, using a SerializationInfo object could completely remove the need
for the VTF ??

Only if the information needed by a GUI serialization consumer is the same
as that needed by a persistence layer consumer. I've argued for some time
that these needs are similar but distinct--for instance, non representable
or private fields might be persisted, and public GUI properties might not be
persisted. Even a BO as a whole might be persistent but have no GUI persence
or vice versa. If you try to service BO serialization to the GUI and
persistance layers with a single serialization implementation you're going
to be making a lot of compromises.

Quote:
Starting the new year with a good argu^H^H^H^H discussion Smile)

Happy New year to all

Yes indeed. Nothing like a (to borrow your phrase) a big wood spoon topic to
start the year off right!

A happy and productive New Year to everyone. :-)

bobD



Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design All times are GMT
Goto page 1, 2, 3, 4  Next
Page 1 of 4

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.