 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Tom Corcoran Guest
|
Posted: Wed Oct 12, 2005 11:35 am Post subject: Value type framwork & calling specific setters |
|
|
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
|
Posted: Wed Oct 12, 2005 1:06 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
"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
|
Posted: Wed Oct 12, 2005 1:51 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
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
|
Posted: Sat Oct 15, 2005 12:58 am Post subject: Re: Value type framwork & calling specific setters |
|
|
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
|
Posted: Mon Nov 28, 2005 3:16 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
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
|
Posted: Tue Nov 29, 2005 3:56 am Post subject: Re: Value type framwork & calling specific setters |
|
|
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
|
Posted: Tue Nov 29, 2005 10:37 am Post subject: Re: Value type framwork & calling specific setters |
|
|
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
|
Posted: Tue Nov 29, 2005 5:54 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
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
|
Posted: Mon Dec 05, 2005 1:29 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
"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
|
Posted: Mon Dec 05, 2005 4:02 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
| 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
|
Posted: Mon Dec 05, 2005 5:34 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
"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
|
Posted: Mon Dec 05, 2005 9:34 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
| Quote: | Not forgetting that my example was only quick demo code
never 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
|
Posted: Tue Dec 20, 2005 4:01 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
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
|
Posted: Tue Dec 20, 2005 5:27 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
"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
|
Posted: Tue Dec 20, 2005 8:10 pm Post subject: Re: Value type framwork & calling specific setters |
|
|
| 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 |
|
 |
|
|
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
|
|