 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Roman Kaßebaum Guest
|
Posted: Wed Dec 29, 2004 2:38 pm Post subject: How to resolve mutual class dependencies |
|
|
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
|
Posted: Wed Dec 29, 2004 3:10 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
"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
|
Posted: Wed Dec 29, 2004 9:22 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
| 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
|
Posted: Thu Dec 30, 2004 3:15 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
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
|
Posted: Thu Dec 30, 2004 5:50 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
| Quote: | {$I Person.inc}
{$I Company.inc}
Yuck!
|
:-)
| 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
|
Posted: Thu Dec 30, 2004 7:53 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
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
|
Posted: Thu Dec 30, 2004 9:40 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
"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
|
Posted: Fri Dec 31, 2004 11:53 am Post subject: Re: How to resolve mutual class dependencies |
|
|
| 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
|
Posted: Fri Dec 31, 2004 2:34 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
"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
|
Posted: Fri Dec 31, 2004 7:13 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
| 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
|
Posted: Sat Jan 01, 2005 12:22 am Post subject: Re: How to resolve mutual class dependencies |
|
|
"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
|
Posted: Sat Jan 01, 2005 11:42 am Post subject: Re: How to resolve mutual class dependencies |
|
|
"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 )
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
|
Posted: Sat Jan 01, 2005 12:48 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
| 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
|
Posted: Sat Jan 01, 2005 1:27 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
| 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 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
|
Posted: Sat Jan 01, 2005 4:22 pm Post subject: Re: How to resolve mutual class dependencies |
|
|
"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 )
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 |
|
 |
|
|
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
|
|