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 

method resolution problems
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design
View previous topic :: View next topic  
Author Message
Lee_Nover
Guest





PostPosted: Fri Feb 11, 2005 6:36 am    Post subject: method resolution problems Reply with quote



I have an interface (ITransportable) that has an Assign method
in the implementing object I'd like to map that to an InternalAssign method
this object also has a virtual Assign method, it's descendants then
override this Assign method to implement the specifics
the problem is when calling eg. IBesedilo.Assign .. it calls the overriden
virtual TBesedilo.Assign method
I guess this happens because IBesedilo descends from IOsnova which
descends from ITransportable and the compiler thinks 'hey, this class has
an Assign method I can use (same params)'
now if I want it to behave as intended then I have to do: (BesediloIntf as
IOsnova).Assign
ofcourse I don't want this, I'd also like to keep the name Assign in both
if I can't get a smart resolution I'll just have to rename the class'
Assign method to smtn else

tnx for any insight :)


here are the basic interfaces and classes:

ITransportable = interface(IInterface)
['{B794D255-C72A-45D9-A34C-FA219D11E316}']
function Clone: ITransportable;
function Load(const AData: Pointer): Boolean;
function Save(const AData: Pointer): Boolean;
function Assign(const ASource: ITransportable): Boolean;
end;

IOsnova = interface(ITransportable)
['{FE74CE9F-8FF4-428F-9801-BC50A0F97BA8}']
function GetDeleted: Boolean;
function GetID: string;
...
end;

IBesedilo = interface(IOsnova)
['{B61BC1B9-F360-484E-BF7F-78D9E28DED65}']
function GetText: string;
procedure SetText(const Value: string);
property Text: string read GetText write SetText;
end;


TOsnova = class(TSubject, IOsnova)
protected
function IOsnova.Assign = InternalAssign;
protected
[..]
function Assign(const ASource: ITransportable): Boolean; virtual;
function Clone: ITransportable; virtual;
[..]
function InternalAssign(const ASource: ITransportable): Boolean;
end;

TBesedilo = class(TOsnova, IBesedilo)
protected
FText: string;
function Assign(const ASource: ITransportable): Boolean; override;
function GetText: string;
function Load(const AData: Pointer): Boolean; override;
function Save(const AData: Pointer): Boolean; override;
procedure SetText(const Value: string);
end;


impl.:


function TOsnova.Assign(const ASource: ITransportable): Boolean;
var
LObj: IOsnova;
begin
Result := Assigned(ASource) and (ASource.QueryInterface(IOsnova, LObj) =
0);
if Result then
begin
FModified:=true;
FNewObject:=LObj.NewObject;
FID:=LObj.ID;
FSifra:=LObj.Sifra;
FNaziv:=LObj.Naziv;
end;
end;

function TOsnova.InternalAssign(const ASource: ITransportable): Boolean;
begin
BeginUpdate;
try
Result:=Assign(ASource);
finally
EndUpdate;
end;
end;


function TBesedilo.Assign(const ASource: ITransportable): Boolean;
var
LObj: IBesedilo;
begin
Result:=inherited Assign(ASource);
if Result and (ASource.QueryInterface(IBesedilo, LObj) = 0) then
begin
FText:=LObj.Text;
end;
end;
Back to top
Lee_Nover
Guest





PostPosted: Fri Feb 11, 2005 7:38 am    Post subject: Re: method resolution problems Reply with quote



Quote:
if I can't get a smart resolution I'll just have to rename the class'
Assign method to smtn else
... and did just that .. rename it to InternalAssign since it's always

gonna be protected
ah well .. :)

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Fri Feb 11, 2005 9:09 am    Post subject: Re: method resolution problems Reply with quote



"Lee_Nover" <Lee_Nover[nospam]@delphi-si.com> a écrit dans le message de
news: opsl0snvabignj8p (AT) istvangx270 (DOT) ..

Quote:
here are the basic interfaces and classes:

ITransportable = interface(IInterface)
['{B794D255-C72A-45D9-A34C-FA219D11E316}']
function Clone: ITransportable;
function Load(const AData: Pointer): Boolean;
function Save(const AData: Pointer): Boolean;
function Assign(const ASource: ITransportable): Boolean;
end;

IOsnova = interface(ITransportable)
['{FE74CE9F-8FF4-428F-9801-BC50A0F97BA8}']
function GetDeleted: Boolean;
function GetID: string;
...
end;

IBesedilo = interface(IOsnova)
['{B61BC1B9-F360-484E-BF7F-78D9E28DED65}']
function GetText: string;
procedure SetText(const Value: string);
property Text: string read GetText write SetText;
end;

Can I just ask why you are deriving your interfaces from each other ?

Does the behaviour of IOsnova really include the behaviour of ITransportable
?

Does the behaviour of IBessedilo really include the behaviour of IOsnova ?

Have you considered the possibility of declaring the interfaces
independently and mixing more than one interface into one class ?

TOsnova = class(TSubject, ITransportable, IOsnova)
protected
function IOsnova.Assign = InternalAssign;
protected
[..]
function Assign(const ASource: ITransportable): Boolean; virtual;
function Clone: ITransportable; virtual;
[..]
function InternalAssign(const ASource: ITransportable): Boolean;
end;

TBesedilo = class(TOsnova, ITransportable, IOsnove, IBesedilo)
protected
FText: string;
function Assign(const ASource: ITransportable): Boolean; override;
function GetText: string;
function Load(const AData: Pointer): Boolean; override;
function Save(const AData: Pointer): Boolean; override;
procedure SetText(const Value: string);
end;

This way you get the flexibility of being able to separate out the
implementation of the interfaces.

Could I also comment that you seem to be echoing the interface hierarchy in
the class hierarchy; this may not always be for the best. Of course you may
have good reason so to do, I am just prompting you to think of alternatives
:-)

Quote:
function TOsnova.Assign(const ASource: ITransportable): Boolean;
var
LObj: IOsnova;
begin
Result := Assigned(ASource) and (ASource.QueryInterface(IOsnova, LObj)
= 0);
if Result then
begin
FModified:=true;
FNewObject:=LObj.NewObject;
FID:=LObj.ID;
FSifra:=LObj.Sifra;
FNaziv:=LObj.Naziv;
end;
end;

You may want to reconsider the design of this function; at the moment, if an
exception were to occur after you assign Result, then the rest of the code
would not be executed and you would have an incorrect result as the function
did not truly succeed.

function TOsnova.Assign(const ASource: ITransportable): Boolean;
var
LObj: IOsnova;
begin
if (ASource <> nil) and Supports(ASource, IOsnova, LObj) then
try
FModified:=true;
FNewObject:=LObj.NewObject;
FID:=LObj.ID;
FSifra:=LObj.Sifra;
FNaziv:=LObj.Naziv;
Result := True;
except
Result := False;
end;
end;

Joanna

--
Joanna Carter (TeamB)

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



Back to top
Lee_Nover
Guest





PostPosted: Fri Feb 11, 2005 10:20 am    Post subject: Re: method resolution problems Reply with quote

Quote:
Can I just ask why you are deriving your interfaces from each other ?

Does the behaviour of IOsnova really include the behaviour of
ITransportable
yep, I want it to have those capabilities


Quote:
Does the behaviour of IBessedilo really include the behaviour of IOsnova
it does: IOsnova (Osnova means Base) has the properties ID and Name

descendants also have these properties

Quote:
Have you considered the possibility of declaring the interfaces
independently and mixing more than one interface into one class ?
I have but I wanted to simplify things and unify common code


Quote:
This way you get the flexibility of being able to separate out the
implementation of the interfaces.
yep, I could do that as well but would mean more changes in an existing

app !
this was the key point actually
maintaining inheritance

for example:
// this is the base _list_ form
// this method opens an input form to add a new object
procedure TSifrantOsnovaF.actNavDodajExecute(Sender: TObject);
var
LNode: PVirtualNode;
LObj: IOsnova;
begin
// EditRazred is an abstract class method that returns the object class
displayed
LObj:=EditRazred.Create();
LObj.NewObject:=true;
with vstMain do
// VnosRazred is an abstract method that returns the associated input
form class
// UrediObjekt is a class method that instantiates the form and edits
the class
if VnosRazred.UrediObjekt(LObj) then
begin
// add the object
DodajObjekt(LObj);
LNode:=AddChild(nil, nil);
FocusToNode(LNode, vstMain);
// update the object remotely
PosodobiObjekt(LObj);
end;
end;



Quote:
Could I also comment that you seem to be echoing the interface hierarchy
in
the class hierarchy; this may not always be for the best. Of course you
may
have good reason so to do, I am just prompting you to think of
alternatives
Smile
mostly the same reasons as above



Quote:
You may want to reconsider the design of this function; at the moment,
if an
exception were to occur after you assign Result, then the rest of the
code
would not be executed and you would have an incorrect result as the
function
did not truly succeed.
the exception would be raised at the top level

eg:

try
OK:=LBesedilo.Assign(LObj);
except
// if an exception occured in the TOsnova.Assign it would show up here
end;

the result is there so I can safely assign _lower_ classes


tnx for the input :)

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Fri Feb 11, 2005 12:14 pm    Post subject: Re: method resolution problems Reply with quote

"Lee_Nover" <Lee_Nover[nospam]@delphi-si.com> a écrit dans le message de
news: opsl020eh4ignj8p (AT) istvangx270 (DOT) ..

If I may continue to stir up your sense of adventure... Smile)

Quote:
Can I just ask why you are deriving your interfaces from each other ?

Does the behaviour of IOsnova really include the behaviour of
ITransportable

yep, I want it to have those capabilities

Does the behaviour of IBessedilo really include the behaviour of IOsnova

it does: IOsnova (Osnova means Base) has the properties ID and Name
descendants also have these properties

If Osnova means Base, then why is it derived from another interface ? IMHO,
the ITransportable interface should be separate and only mixed in in the
TOsnova class; you might not see the advantages immediately, but they will
become apparent as the system grows.

Quote:
yep, I could do that as well but would mean more changes in an existing
app !
this was the key point actually
maintaining inheritance

I have no doubt as to your intent; it's just that you may benefit from
reviewing some of your interface inheritance and implementation to help
avoid the method resolutoin issues that prompted your OP.

Quote:
the exception would be raised at the top level
eg:

try
OK:=LBesedilo.Assign(LObj);
except
// if an exception occured in the TOsnova.Assign it would show up here
end;

You should either rely on the exception alone and change the boolean
function to a procedure or keep the function and not rely on the exception.
Don't mix the two types of flow control, it will be easier to debug if you
only do the one.

Feel free to ignore this advice, but it just might come in useful later :-)

Joanna

--
Joanna Carter (TeamB)

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



Back to top
Jim Cooper
Guest





PostPosted: Fri Feb 11, 2005 12:28 pm    Post subject: Re: method resolution problems Reply with quote


Quote:
you may benefit from reviewing some of your interface inheritance

I would go so far as to say interface inheritance is approaching a bad
smell. If it mirrors a class inheritance hierarchy I would say it is
definitely smelly :-)

In the example given originally there is actually no need for interfaces
(bar reference counting). However, this is presumably a portion of the
places the interfaces are used. Got some more of the interface/class
hierarchy?

Cheers,
Jim Cooper

__________________________________________

Jim Cooper [email]jcooper (AT) tabdee (DOT) ltd.uk[/email]
Tabdee Ltd http://www.tabdee.ltd.uk

TurboSync - Connecting Delphi to your Palm
__________________________________________

Back to top
Lee_Nover
Guest





PostPosted: Fri Feb 11, 2005 12:33 pm    Post subject: Re: method resolution problems Reply with quote

Quote:
If I may continue to stir up your sense of adventure... Smile)
sure Very Happy


Quote:
If Osnova means Base, then why is it derived from another interface ?
it's the base of BO hieararchy

if not inherited from ITransportable then I'd have to get ITransportable
everytime I wanted to assign or load something

var LObj: ITransportable;
begin
if ANObject.QueryInterface(ITransportable, LObj) = 0 then
LObj.Assign(Something);

now I simply call ANObject.Assign(Something)

Quote:
I have no doubt as to your intent; it's just that you may benefit from
reviewing some of your interface inheritance and implementation to help
avoid the method resolutoin issues that prompted your OP.
already removed that .. but will review the whole thing once I get a day

or two for it :)


Quote:
You should either rely on the exception alone and change the boolean
function to a procedure or keep the function and not rely on the
exception.
Don't mix the two types of flow control, it will be easier to debug if
you
only do the one.
it certainly shouldn't raise an exception in my case

the design allows for exception free assignments
let's say I have TPerson > TCustomer, I could assign them in any direction
maybe I need to sleep on it all to get a clearer view :)


Quote:
Feel free to ignore this advice, but it just might come in useful later
Smile
I don't ignore any advice .. all are usefull .. specially if they provide

another view

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Fri Feb 11, 2005 12:34 pm    Post subject: Re: method resolution problems Reply with quote

"Jim Cooper" <jcooper (AT) tabdee (DOT) ltd.uk> a écrit dans le message de news:
420ca4dd$1 (AT) newsgroups (DOT) borland.com...

Quote:
I would go so far as to say interface inheritance is approaching a bad
smell. If it mirrors a class inheritance hierarchy I would say it is
definitely smelly Smile

Hi Jim, I was just being tactful :-)

Joanna

--
Joanna Carter (TeamB)

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



Back to top
Lee_Nover
Guest





PostPosted: Fri Feb 11, 2005 12:46 pm    Post subject: Re: method resolution problems Reply with quote

Quote:
I would go so far as to say interface inheritance is approaching a bad
smell. If it mirrors a class inheritance hierarchy I would say it is
definitely smelly Smile
Very Happy



Quote:
In the example given originally there is actually no need for interfaces
true, I was thinking about doing it classes only but decided I'd go with

interfaces in case it gets more complex

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Fri Feb 11, 2005 1:03 pm    Post subject: Re: method resolution problems Reply with quote

"Lee_Nover" <Lee_Nover[nospam]@delphi-si.com> a écrit dans le message de
news: opsl086xikignj8p (AT) istvangx270 (DOT) ..

Quote:
If Osnova means Base, then why is it derived from another interface ?

it's the base of BO hieararchy
if not inherited from ITransportable then I'd have to get ITransportable
everytime I wanted to assign or load something

var LObj: ITransportable;
begin
if ANObject.QueryInterface(ITransportable, LObj) = 0 then
LObj.Assign(Something);

Once again IMHO, Assign is definitely a BO interface function, but the other
storage methods should only be accessible if the BO is meant to be stored.
Don't forget you should habe BOs in a good system that are transitory and
therefore could be Assigned but should not support being Loaded, etc.

Also do yourself a great favour and start using Supports instead of
QueryInterface; it does the same job but doesn't need testing against 0.

it certainly shouldn't raise an exception in my case
the design allows for exception free assignments
let's say I have TPerson > TCustomer, I could assign them in any direction
maybe I need to sleep on it all to get a clearer view :)

I would suggest two things that could bite you here :-)

1. All Customers can be assumed to be Persons, but not necessarily the other
way around.

2. If there is s possibility that a Customer could also be a Supplier (or
any other derivative) then you should use the concept of Roles rather than
inheritance.

e.g.

TRole = class(...)
...
end;

TRoleClass = class of TRole;

TCustomer = class(TRole)
...
end;

TSupplier = class(TRole)
...
end;

TPerson = class(...)
...
procedure AddRole(role: TRole);
function SupportsRole(roleClass: TRoleClass): TRole;
end;

Of course this could also be done with interfaces.

Joanna

--
Joanna Carter (TeamB)

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



Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Fri Feb 11, 2005 1:05 pm    Post subject: Re: method resolution problems Reply with quote

"Lee_Nover" <Lee_Nover[nospam]@delphi-si.com> a écrit dans le message de
news: opsl09rtqdignj8p (AT) istvangx270 (DOT) ..

true, I was thinking about doing it classes only but decided I'd go with
interfaces in case it gets more complex

Now you really are taking your life into your hands; standing between Jim
and me when we dicuss the [over/under]use of interfaces Smile)

Joanna

--
Joanna Carter (TeamB)

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


Back to top
Lee_Nover
Guest





PostPosted: Fri Feb 11, 2005 1:29 pm    Post subject: Re: method resolution problems Reply with quote

Quote:
Once again IMHO, Assign is definitely a BO interface function, but the
other
storage methods should only be accessible if the BO is meant to be
stored.
in my case all current are

but I understand what you mean .. I just won't descend them from I/TOsnova
this is the base for the objects that can be stored (transfered)


Quote:
Don't forget you should habe BOs in a good system that are transitory and
therefore could be Assigned but should not support being Loaded, etc.
don't quite understand what you mean



Quote:
Also do yourself a great favour and start using Supports instead of
QueryInterface; it does the same job but doesn't need testing against 0.
just a habbit I guess Smile



Quote:
I would suggest two things that could bite you here :-)

1. All Customers can be assumed to be Persons, but not necessarily the
other way around.
true .. but I can still assign the same properties from one to another

in the second case I'll have to handle this differently then


Quote:
2. If there is s possibility that a Customer could also be a Supplier (or
any other derivative) then you should use the concept of Roles rather
than
inheritance.

e.g.

TRole = class(...)
...
end;

TRoleClass = class of TRole;

TCustomer = class(TRole)
...
end;

TSupplier = class(TRole)
...
end;

TPerson = class(...)
...
procedure AddRole(role: TRole);
function SupportsRole(roleClass: TRoleClass): TRole;
end;
haven't had the need for it and our company logic doesn't distinct one

from another ..
... no customer has wanted that yet :)

but if I need a person type I'll do it this way, tnx for suggesting it :)

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Fri Feb 11, 2005 2:13 pm    Post subject: Re: method resolution problems Reply with quote

"Lee_Nover" <Lee_Nover[nospam]@delphi-si.com> a écrit dans le message de
news: opsl1bqse3ignj8p (AT) istvangx270 (DOT) ..

Quote:
Don't forget you should have BOs in a good system that are transitory
and
therefore could be Assigned but should not support being Loaded, etc.

don't quite understand what you mean

In most business systems there are business objects that need displaying and
editing, but their sole purpose is to manipulate objects that need storing;
they themselves don't need storing.

Such objects require all the expected BO behaviour - apart from being
persistent (they can be said to be transitory).

Separating out the persistence interface allows you to ensure that you don't
pass such a BO to your storage mechanism and allows you to test whether the
object is storable.

If you are only starting to design OO systems, coming from a database
background, it is quite common to only think of BOs as those classes which
used to be tables in a database.

If you have the time, take another look at the BOs in your system and then
look at any other code that manipulates those objects. If the manipulating
code is on forms, then that could well be candidate code for non-persistent
BO classes.

Joanna

--
Joanna Carter (TeamB)

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



Back to top
Jim Cooper
Guest





PostPosted: Fri Feb 11, 2005 3:45 pm    Post subject: Re: method resolution problems Reply with quote


Quote:
Now you really are taking your life into your hands; standing between Jim
and me when we dicuss the [over/under]use of interfaces Smile)

Absolutely :-)

Lee, IMO, if they aren't needed, don't use interfaces. This particular
example is overly complicated for no reason. It makes a great deal of
sense to have a base business object class in any form of OPF, as there
is behaviour that is common to all BOs. It is possible to do the same
thing with interfaces, so that you could in effect have many base BO
classes, but your life will be simpler if you can manage with them :-)

The more I program, the more I like the idea of not writing code I'll
never use Smile The refactoring world talks about a bad smell called
Speculative Generality, and this code is a good example. It's not wrong
per se, but it's more complicated than it needs to be, without giving
you any benefit **now** (it's actually cost you time because stuff isn't
working right, and we're having all these discussions <g>). You've
actually said you used interfaces "in case it gets more complex". But
what if it never does? You've wasted time and effort and your code is
not as easy to read.

What I do more and more is add things when they're needed, and not
before. I trust that I can refactor things should it be necessary. It's
hard to give an example of what I mean, but these days I tend to write
code that is easy to refactor.

There are exceptions to this, of course. When writing frameworks to be
used by others, for instance, it's best not to make too many changes to
the public interface (in the declaration sense of the word, not the
IInterface sense) too often.

However, in your particular example, I think you could do without
interfaces altogether. In fact, I think you should collapse your
hierarchy into one base BO class.

Cheers,
Jim Cooper

__________________________________________

Jim Cooper [email]jcooper (AT) tabdee (DOT) ltd.uk[/email]
Tabdee Ltd http://www.tabdee.ltd.uk

TurboSync - Connecting Delphi to your Palm
__________________________________________

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Fri Feb 11, 2005 4:12 pm    Post subject: Re: method resolution problems Reply with quote

"Jim Cooper" <jcooper (AT) tabdee (DOT) ltd.uk> a écrit dans le message de news:
420cd322$1 (AT) newsgroups (DOT) borland.com...

Quote:
However, in your particular example, I think you could do without
interfaces altogether. In fact, I think you should collapse your
hierarchy into one base BO class.

OTOH.... ;~}

Joanna

--
Joanna Carter (TeamB)

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



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  Next
Page 1 of 3

 
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.