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 

Value type framwork & calling specific setters
Goto page 1, 2  Next
 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design
View previous topic :: View next topic  
Author Message
Tom Corcoran
Guest





PostPosted: Wed Oct 12, 2005 11:35 am    Post subject: Value type framwork & calling specific setters Reply with quote



We are working on converting our opf to a value type framework, we do
not use interfaces.

Previously as part of an object we would :
property Name : string read FString write SetName;

Now instead we will have TOurString, so, this become
property Name : TOurString read FString write TOurString;
where TOurString has a Value property of type string.

Previously
Name := 'my string';
called the setter SetName.

We still need this setter to be called but doing
Name.Value := 'my string';
bypasses the setter. To call the setter I need to do something of the
effect of the unworkable :
Name := TOurString('my string').....

Once could introduce an owner into TOurString and
Value could have a setter, but I can't see how one could call
the corresponding setter in the owner - SetName.

There must be a way of doing this?

Please let me know if I have not explained this well enough.

Thanks a lot,

Tom.
Back to top
Joanna Carter [TeamB]
Guest





PostPosted: Wed Oct 12, 2005 1:06 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote



"Tom Corcoran" <tomnospam.corcoran (AT) sportstgnospam (DOT) com> a écrit dans le
message de news: 434cf45a$2 (AT) newsgroups (DOT) borland.com...

Quote:
We are working on converting our opf to a value type framework, we do
not use interfaces.

Previously as part of an object we would :
property Name : string read FString write SetName;

Now instead we will have TOurString, so, this become
property Name : TOurString read FString write TOurString;
where TOurString has a Value property of type string.

Previously
Name := 'my string';
called the setter SetName.

We still need this setter to be called but doing
Name.Value := 'my string';
bypasses the setter. To call the setter I need to do something of the
effect of the unworkable :
Name := TOurString('my string').....

Once could introduce an owner into TOurString and
Value could have a setter, but I can't see how one could call
the corresponding setter in the owner - SetName.

There must be a way of doing this?

Add a private string/object list for your value types to the base BO class.
Add an appropriate value type object for each property to that list in the
constructor.
Add one protected getter/setter method per type in the base class that takes
the name of the property as a parameter.

TBO = class
private
fValueTypes: TStringList;
protected
function GetStringValue(const name: string): string;
function GetIntegerValue(const name: string): Integer;
...etc
procedure SetStringValue(const name: string; const value: string);
procedure SetIntegerValue(name: string; value: Integer);
...etc

implementation

function TBO.GetValue(name: string): Integer;
begin
Result := TIntegerValueType(fValueTypes[name].Object).Value;
end;

....

Then in your business classes

e.g.

TCustomer = class(TBO)
private
function GetName: string;
procedure SetName(const value string);
public
property Name: string
read GetName
write SetName;

implementation

function TCustomer.GetName: string;
begin
Result := GetStringValue("Name");
end;

procedure TCustomer.SetName(const value string);
begin
// do validation
SetStringValue("Name", value);
end;

Then you can call the properties as you would if they were normal types

aCustomer.Name := "Joanna";

Does that help ?

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer



Back to top
Iman L Crawford
Guest





PostPosted: Wed Oct 12, 2005 1:51 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote



Tom Corcoran <tomnospam.corcoran (AT) sportstgnospam (DOT) com> wrote in
news:434cf45a$2 (AT) newsgroups (DOT) borland.com:
Quote:
property Name : TOurString read FString write TOurString;

you could try something like

TMyClass = class(TObject)
private
FOurString: TOurString;
function getString: string;
procedure setString(const AString: string);
public
property Name: string read getString write setString;
end;

procedure setString(const AString: string);
begin
FOurString.Value := AString;
end;

function getString: string;
begin
result := FOurString.Value;;
end;



--
Iman



Back to top
Marcos
Guest





PostPosted: Sat Oct 15, 2005 12:58 am    Post subject: Re: Value type framwork & calling specific setters Reply with quote

We are creating the Infra Framework. we build our classes like Iman. The
framework manage the attribtutes. Infra has IInfraTypes (ValueType
framework) yet. The code below is all generated by Infragen (Infra Code
generator).

TMyClass = class(TObject)
private
FName: IInfraString;
function getName: string;
procedure setName(const AString: string);
public
property Name: string read getName write setName;
public
procedure AfterConstruction: override;
end;

procedure TMyClass.AfterConstruction;
begin
inherited;
FName := AddFeature('Name') as IInfraString;
end;

function TMyClass.getString: string;
begin
result := FName.AsString;
end;

procedure TMyClass.setString(const AString: string);
begin
FName.AsString := AString;
end;
Back to top
Tom Corcoran
Guest





PostPosted: Mon Nov 28, 2005 3:16 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote

Joanna Carter [TeamB] wrote:
Quote:
"Tom Corcoran" <tomnospam.corcoran (AT) sportstgnospam (DOT) com> a écrit dans le
message de news: 434cf45a$2 (AT) newsgroups (DOT) borland.com...

| We are working on converting our opf to a value type framework, we do
| not use interfaces.
|
| Previously as part of an object we would :
| property Name : string read FString write SetName;
|
| Now instead we will have TOurString, so, this become
| property Name : TOurString read FString write TOurString;
| where TOurString has a Value property of type string.
|
| Previously
| Name := 'my string';
| called the setter SetName.
|
| We still need this setter to be called but doing
| Name.Value := 'my string';
| bypasses the setter.

Add a private string/object list for your value types to the base BO class.
Add an appropriate value type object for each property to that list in the
constructor.
Add one protected getter/setter method per type in the base class that takes
the name of the property as a parameter.

TBO = class
private
fValueTypes: TStringList;
protected
function GetStringValue(const name: string): string;
function GetIntegerValue(const name: string): Integer;
...etc
procedure SetStringValue(const name: string; const value: string);
procedure SetIntegerValue(name: string; value: Integer);
...etc

implementation

function TBO.GetValue(name: string): Integer;
begin
Result := TIntegerValueType(fValueTypes[name].Object).Value;
end;

...

TCustomer = class(TBO)
private
function GetName: string;
procedure SetName(const value string);
public
property Name: string
read GetName
write SetName;

implementation

function TCustomer.GetName: string;
begin
Result := GetStringValue("Name");
end;

procedure TCustomer.SetName(const value string);
begin
// do validation
SetStringValue("Name", value);
end;

Then you can call the properties as you would if they were normal types


Thanks a lot for all the replies, everyone. Priorities changed there for
a while so I am only coming back to this now.

One of the benefits of having our own types was to be able to go
MyTpe.Whatever but with this technique it would seem to mean that a
Whatever getter would need to be applied in each object.

Maybe I am missing something.... also, why do you use a TStringList for
the fValueTypes? Is it because your method does not use a TOurString
instance for each new string type but add to the TBO instance
(fValueTypes) each time and use GetStringValue and the like.

Iman L Crawford wrote:
Quote:
property Name : TOurString read FString write TOurString;

you could try something like

TMyClass = class(TObject)
private
FOurString: TOurString;
function getString: string;
procedure setString(const AString: string);
public
property Name: string read getString write setString;
end;

procedure setString(const AString: string);
begin
FOurString.Value := AString;
end;

function getString: string;
begin
result := FOurString.Value;;
end;

The way we were envisaging was more like Iman and Marcos but we were
defining Name as a TOurString. That would allow us to do a
Name.Whatever, but does lead to the complication questioned in this thread.

Any further commentary appreciated.

Thanks, Tom.



Back to top
Marcos
Guest





PostPosted: Tue Nov 29, 2005 3:56 am    Post subject: Re: Value type framwork & calling specific setters Reply with quote

Tom Corcoran escreveu:
Quote:
Thanks a lot for all the replies, everyone. Priorities changed there for
a while so I am only coming back to this now.

One of the benefits of having our own types was to be able to go
MyTpe.Whatever but with this technique it would seem to mean that a
Whatever getter would need to be applied in each object.

What u means with MyTpe.Whatever? What u intend to do?

Quote:
The way we were envisaging was more like Iman and Marcos but we were
defining Name as a TOurString. That would allow us to do a
Name.Whatever, but does lead to the complication questioned in this thread.

On Infra u can use Name with TOurString or IInfraString too. We gave a
alternative to people that can use primitive types and have more
metadata information about this type. just this. But Infra not is just a
ValueType Framework. It is:

Notification Framework;
ValueType Framework
Reflection Framework;
Aspect Framework
Interface Injection Framework
Model-View-Presenter Framework

and soon:
Persistence Framework
OCL Parser

The Infra has yet a tool called InfraGen that will generate all code to
delphi, c#, .NEt or Java

Back to top
Tom Corcoran
Guest





PostPosted: Tue Nov 29, 2005 10:37 am    Post subject: Re: Value type framwork & calling specific setters Reply with quote

Marcos wrote:
Quote:
Tom Corcoran escreveu:

Thanks a lot for all the replies, everyone. Priorities changed there
for a while so I am only coming back to this now.

One of the benefits of having our own types was to be able to go
MyTpe.Whatever but with this technique it would seem to mean that a
Whatever getter would need to be applied in each object.


What u means with MyTpe.Whatever? What u intend to do?

I just meant that if we had our own datatypes, then in the future if we
decided to add the method, eg. WhatLanguagesDoISpeak we could then do a
MyType.WhatLanguagesDoISpeak everywhere rather than having to do an
implementation for each type.

Good luck with your framework.

Thanks, Tom.

Back to top
Solerman Kaplon
Guest





PostPosted: Tue Nov 29, 2005 5:54 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote

Marcos escreveu:
Quote:
TMyClass = class(TObject)

TMyClass = class(TInfraObject, IMyClass)

Otherwise, you may leave ppl wondering where AddFeature cames from :-)

Solerman

Back to top
Joanna Carter [TeamB]
Guest





PostPosted: Mon Dec 05, 2005 1:29 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote

"Tom Corcoran" <tomnospam.corcoran (AT) sportstgnospam (DOT) com> a écrit dans le
message de news: [email]438B1F42.2070201 (AT) sportstgnospam (DOT) com[/email]...

Quote:
Maybe I am missing something.... also, why do you use a TStringList for
the fValueTypes? Is it because your method does not use a TOurString
instance for each new string type but add to the TBO instance
(fValueTypes) each time and use GetStringValue and the like.

Using a TStringList is one way of indexing the Value Types by string names;
so you get :

fValues.AddObject('Name', TStringValueType.Create);
fValues.AddObject('Age', TIntegerValueType.Create);

and :

var
value: Integer;
begin
value := TIntegerValueType(fValues.Objects[fValues.IndexOf('Age')]).Value;
...
end;

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer



Back to top
Lee_Nover
Guest





PostPosted: Mon Dec 05, 2005 4:02 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote

Quote:
Using a TStringList is one way of indexing the Value Types by string names;
so you get :

... a dead slow system
better use a hashed list

in DePO2 we have support for named attributes:
function GetAttribute(const Name: string): Tdpo2ValueType;
procedure SetAttribute(const Name: string; const AAttribute: Tdpo2ValueType);
property Attribute[const Name: string]: Tdpo2ValueType read GetAttributewrite SetAttribute; default;

function Tdpo2Object.GetAttribute(const Name: string): Tdpo2ValueType;
var
LIndex: Integer;
begin
LIndex := FAttributes.IndexOf(Name);
if LIndex <> -1 then
Result := Tdpo2ValueType(FAttributes.Objects[LIndex])
else
Result := nil;
end;



we register the attributes in the RegisterAttributes method using RegisterAttribute :)

procedure RegisterAttribute(const AAttribute: Tdpo2ValueType); overload;
function RegisterAttribute(const AClass: Tdpo2ValueTypeClass;
const AName: string; const APersistent: Boolean = True): Pointer; overload;

impl:


procedure Tdpo2Object.RegisterAttribute(const AAttribute: Tdpo2ValueType);
begin
Assert(AAttribute.Name <> '', 'Attribute name must not be empty');
FAttributes.AddObject(AAttribute.Name, AAttribute);
(AAttribute as ISubject).Attach(Self as IObserver);
end;

function Tdpo2Object.RegisterAttribute(const AClass: Tdpo2ValueTypeClass;
const AName: string; const APersistent: Boolean = True): Pointer;
var
LObj: Tdpo2ValueType;
begin
LObj := AClass.Create(Self);
LObj.Name := AName;
LObj.Persistent := APersistent;
RegisterAttribute(LObj);
Result := LObj;
end;



and as an example:

type
TUser = class(Tdpo2Object)
protected
FAddress: Tdpo2String;
FName: Tdpo2String;
FPhones: TPhones;
FSurname: Tdpo2String;
function GetAsString: string; override;
function GetIDClass: Tdpo2ValueTypeClass; override;
procedure RegisterAttributes; override;
procedure SetAsString(const Value: string); override;
public
destructor Destroy; override;
property Address: Tdpo2String read FAddress;
property Name: Tdpo2String read FName;
property Phones: TPhones read FPhones;
property Surname: Tdpo2String read FSurname;
end;

procedure TUser.RegisterAttributes;
begin
inherited;
FAddress := RegisterAttribute(Tdpo2String, 'Address');
FName := RegisterAttribute(Tdpo2String, 'Name');
FPhones := RegisterAttribute(TPhones, 'Phones');
FPhones.ItemClass := TPhone;
FSurname := RegisterAttribute(Tdpo2String, 'Surname');
FPersistent := True;
(Self as Idpo2Value).Name := 'User';
end;


so we can use either User.Name.AsString or User['Name'].AsString

Back to top
Joanna Carter [TeamB]
Guest





PostPosted: Mon Dec 05, 2005 5:34 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote

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

Quote:
Using a TStringList is one way of indexing the Value Types by string
names;
so you get :

.. a dead slow system
better use a hashed list

Not forgetting that my example was only quick demo code :-)

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer



Back to top
Lee_Nover
Guest





PostPosted: Mon Dec 05, 2005 9:34 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote

Quote:
Not forgetting that my example was only quick demo code Smile
never Smile that's why I always do my own implementation (if needed)

hopefully I'll get more time to work on finishing DePO2

Back to top
Tom Corcoran
Guest





PostPosted: Tue Dec 20, 2005 4:01 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote

Joanna Carter [TeamB] wrote:
Quote:
"Tom Corcoran" <tomnospam.corcoran (AT) sportstgnospam (DOT) com> a écrit dans le
message de news: [email]438B1F42.2070201 (AT) sportstgnospam (DOT) com[/email]...

| Maybe I am missing something.... also, why do you use a TStringList for
| the fValueTypes? Is it because your method does not use a TOurString
| instance for each new string type but add to the TBO instance
| (fValueTypes) each time and use GetStringValue and the like.

Using a TStringList is one way of indexing the Value Types by string names;
so you get :

fValues.AddObject('Name', TStringValueType.Create);
fValues.AddObject('Age', TIntegerValueType.Create);

and :

var
value: Integer;
begin
value := TIntegerValueType(fValues.Objects[fValues.IndexOf('Age')]).Value;
...
end;

Thanks for the post. In your example it seems there is only one instance
of TBO that stores all the types? I guess that's my confusion on why
there is a stringList as in our case we have set it up so all our types
are a descendant of our base class.

Have not able to figure out a solution yet. We don't want to have to
write getter and setter code for each method added for each type
instance, as I think this method suggests, i'm sure it doesn't but I
can't quiet get my head around it.

Happy holidays.

Tom.

Back to top
Joanna Carter [TeamB]
Guest





PostPosted: Tue Dec 20, 2005 5:27 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote

"Tom Corcoran" <tomnospam.corcoran (AT) sportstgnospam (DOT) com> a écrit dans le
message de news: [email]43A82AF1.1070502 (AT) sportstgnospam (DOT) com[/email]...

Quote:
Thanks for the post. In your example it seems there is only one instance
of TBO that stores all the types? I guess that's my confusion on why
there is a stringList as in our case we have set it up so all our types
are a descendant of our base class.

Maybe you have the wrong terminology but the TBO class is a base class, from
which all your business classes need to derive.

You say that there is inly one instance; this is not so as each instance of
a business class like TCustomer, TOrder, etc is also an instance of TBO, as
the business class derive from TBO.

Every business object needs a list of Value Types to hold the values behind
the properties, the TStringList, or better still THashedStringList is the
list that holds the Value Types.

TBO contains a private list for Value Types; the TBO virtual constructor
creates an instance of that list and the destructor detroys that list.

TBO should also have a protected method that allows you to add Value Types
to the list for access by the properties of derived classes.

And TBO contains protected getter methods like :

function GetStringValue(const name: string): string;
function GetIntegerValue(const name: string): Integer;
// etc

.... that allow you to get at the real value stored in the Value Types in the
list.

Protected setter methods like :

procedure SetStringValue(const name: string; const value: string);
procedure SetIntegerValue(name: string; value: Integer);
// etc

.... allow you to set the real values that will be stored in the Value Types
in, the list.

Business classes like Customer, Order, etc have to add one Value Type object
of an appropriate type to the list in the inherited BO class in their
constructor.

So for a example, a Customer class would look something like this :

TCustomer = class(TBO)
private
function GetName: string;
procedure SetName(const value string);
...
public
property Name: string
read GetName
write SetName;
...
constructor Create; override;
end;

You need one property which should be of the *real* type that you want the
property to reflect; e.g. string, integer, double, TDateTime, etc. You
should *not* use the Value Types as the type of the properties, the getter
and setter methods will take care of translating between the *real* values
and the Value Types.

The constructor will look something like this :

constructor TCustomer.Create;
begin
inherited Create; // initialises the value type list in TBO.Create
AddValueType('Name', TStringValueType.Create);
AddValueType('Age', TIntegerValueType.Create);
// etc
end;

Then, as I said in my example, you need to add similar code to this :

function TCustomer.GetName: string;
begin
Result := GetStringValue("Name");
end;

procedure TCustomer.SetName(const value string);
begin
// do validation
SetStringValue("Name", value);
end;

.... in the getter and setter methods for each

Quote:
Have not able to figure out a solution yet. We don't want to have to
write getter and setter code for each method added for each type
instance, as I think this method suggests, i'm sure it doesn't but I
can't quiet get my head around it.

There is no way of avoiding having to write getter and setter methods for
each property in regardless of what version of Delphi or even other language
that you choose. Delphi for Win32 or Delphi for .NET 1.0 also require that
you add the Value Types in the constructor of each business class; the only
way around this will be when Delphi supports .NET 2.0 generic types in the
next Highlander release, where youwill be able to use .NET reflection in the
TBO constructor to enumerate through all the properties declared in your
derived business class and add the Value Types there.

Here is the actual code for a test business class that we have used in
pre-production tests for our frameworks :

type
TCustomer = class(TBusinessObject)
private
function GetCode: string;
function GetName: string;
function GetTotalOnOrder: Double;
function GetTotalShipped: Double;
procedure SetCode(const Value: string);
procedure SetName(const Value: string);
procedure SetTotalOnOrder(Value: Double);
procedure SetTotalShipped(Value: Double);
public
constructor Create; override;
property Code: string
read GetCode
write SetCode;
property Name: string
read GetName
write SetName;
property TotalOnOrder: Double
read GetTotalOnOrder
write SetTotalOnOrder;
property TotalShipped: Double
read GetTotalShipped
write SetTotalShipped;
end;

implementation

const // ValueType names to avoid spelling inconsistencies
sCustomerCode = 'Code';
sCustomerName = 'Name';
sCustomerTotalOnOrder = 'TotalOnOrder';
sCustomerTotalShipped = 'TotalShipped';

constructor TCustomer.Create
begin
AddValueType(sCustomerCode, TStringValueType);
AddValueType(sCustomerName, TStringValueType);
AddValueType(sCustomerTotalOnOrder, TFloatValueType);
AddValueType(sCustomerTotalShipped, TFloatValueType);
end;

function TCustomer.GetCode: string;
begin
Result := GetStringValue(sCustomerCode);
end;

function TCustomer.GetName: string;
begin
Result := GetStringValue(sCustomerName);
end;

function TCustomer.GetTotalOnOrder: Double;
begin
Result := GetFloatValue(sCustomerTotalOnOrder);
end;

function TCustomer.GetTotalShipped: Double;
begin
Result := GetFloatValue([sCustomerTotalShipped);
end;

procedure TCustomer.SetCode(const Value: string);
begin
SetStringValue(sCustomerCode, Value);
end;

procedure TCustomer.SetName(const Value: string);
begin
SetStringValue(sCustomerName, Value);
end;

procedure TCustomer.SetTotalOnOrder(Value: Double);
begin
SetFloatValue(sCustomerTotalOnOrder, Value);
end;

procedure TCustomer.SetTotalShipped(Value: Double);
begin
SetFloatValue(sCustomerTotalShipped, Value);
end;

The following is an (partial) example of how you would iterate through the
properties of a class in the constructor of the BO class, using C# 2.0
generics :

{
Type vtType = null;

PropertyInfo[] properties = GetType().GetProperties();

foreach (PropertyInfo propInfo in properties)
{
Type[] genericValueTypeArgs = new Type[] { propInfo.PropertyType };

vtType = typeof(ValueType<>).MakeGenericType(genericValueTypeArgs);

ValueType vt = (ValueType) Activator.CreateInstance(vtType);

valueTypes.Add(propInfo.Name, vt);
}
}

All this saves is the extra constructor code in each business class, you
would still have to write accessor methods for each property.

Does this help, or can you tell us what is it you are still not
understanding ?

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer



Back to top
Bart
Guest





PostPosted: Tue Dec 20, 2005 8:10 pm    Post subject: Re: Value type framwork & calling specific setters Reply with quote


Quote:
function TCustomer.GetName: string;
begin
Result := GetStringValue(sCustomerName);
end;


procedure TCustomer.SetName(const Value: string);
begin
SetStringValue(sCustomerName, Value);
end;


Joanna why are not you using objects as ValueTypes ?

Correct me if I am wrong but as I see it now it has several advantages:

1. You don't have to write all the getters and setters in the business
object.
2. It is easy to add extra information i.e. max. length, min. value, max.
value etc. etc.
3. The value types can be a subject. So they are pretty easy to 'wire' with
standard controls

I hope you don't mind I jumped in this discussion. Can you explain ?

Bart



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

 
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.