Wednesday, April 13, 2005

OPF.Value Type Framework.2

From: Joanna Carter \(TeamB\)
Subject: Re: Correct design ?





Date: 2004-11-22 01:17:25 PST
"Alan"  a écrit dans le message de news:
41a12948@newsgroups.borland.com...

Let me start by recommending you look at the concept of OPFs (Object
Persistence Frameworks); there are some articles on my website
www.carterconsulting.org.uk

Now for some constructive criticism :

Although you seem to be removing the concepts of database tables from the
UI, you are still linking the Business Objects very firmly to the database
tables.

Your Employee DataModule class has to know about the Employee Business
Object class and the Employee Business Object class has to know about the
Employee DataModule class. This means that both classes have to reside in
the same unit to avoid circular reference problems; not a good idea.

You also require the UI to know the ID of the object before you can get the
details; most users tend to know an employees name better than they know a
number.

Now for some suggestions :

You need to remove the knowledge of any data mechanism from your busines
objects, so you get a business class like this :

TEmployee = class
private
function GetLastName: String;
function GetFirstName: String;
procedure SetLastName(aValue: String);
procedure SetFirstName(aValue: String);
public
property LastName: String
read GetLastName
write SetLastName;
property FirstName: String
read GetFirstName
write SetFirstName;
end;

The business class can then make use of a Value Type Framework to allow you
to get at the values in the private fields.

TValueEnum = (veString, veInteger, ...);

TValueType = class
private
fName: string;
fEnum: TValueEnum;
protected
procedure SetEnum(Value: TValueEnum);
public
constructor Create(const Name: string = ''); virtual;
property Name: string
read fName;
property ValueEnum: TValueEnum
read fEnum;
end;

TStringValueType = class(TValueType)
private
fValue: string;
procedure SetValue(const Value: string);
public
constructor Create(const Name: string = ''); override;
property Value: string
read fValue
write SetValue;
end;

constructor TStringValueType.Create(const Name: string = '');
begin
inherited Create(Name);
SetEnum(veString);
end;

TIntegerValueType = class(TValueType)
private
fValue: Integer;
procedure SetValue(Value: Integer);
public
constructor Create(const Name: string = ''); override;
property Value: Integer
read fValue
write SetValue;
end;

constructor TIntegerValueType.Create(const Name: string = '');
begin
inherited Create(Name);
SetEnum(veInteger);
end;

TxxxValueType......

TObjectValueType = class(TValueType)
private
fValueTypes: TValueTypeList;
protected
procedure CreateValueTypes; virtual;
function GetValueType(const ValueTypeName: string): TValueType;
public
constructor Create(const Name: string = ''); override;
function GetValueTypes: TValueTypeList;
end;

constructor TObjectValueType.Create(const Name: string = '');
begin
inherited Create(Name);
SetEnum(veObject);
CreateValueTypes;
end;

procedure TObjectValueType.CreateValueTypes; virtual;
begin
fValueTypes := TValueTypeList.Create;
fValueTypes.Add(TIntegerValueType.Create('ID');
end;

Now you can alter your Employee class to derive from TObjectValueType :

TEmployee = class(TObjectValueType)
private
function GetLastName: String;
function GetFirstName: String;
procedure SetLastName(const Value: String);
procedure SetFirstName(const Value: String);

protected
procedure CreateValueTypes; override;
public
property LastName: String
read GetLastName
write SetLastName;
property FirstName: String
read GetFirstName
write SetFirstName;
end;

procedure TEmployee.CreateValueTypes;
begin
inherited CreateValueTypes;
fValueTypes.Add(TStringValueType.Create('FirstName');
fValueTypes.Add(TStringValueType.Create('LastName');
end;

function TEmployee.GetLastName: String;
begin
Result := TStringValueType(GetValueType('LastName')).Value;
end;

procedure TEmployee.SetLastName(const Value: String);
begin
TStringValueType(GetValueType('LastName')).Value := Value;
end;

...

Then I would suggest you look at the articles on OPFs to see how to get
objects from storage.

Essentially; the OPF will talk to the Value Types something like this :

procedure PopulateObject(Obj; TObjectValueType);
var
i: Integer;
vt: TValueType;
begin
for i := 0 to Obj.GetValueTypes.GetCount - 1 do
begin
vt := Obj.GetValueTypes[i];
case vt.ValueEnum of
veString:
TStringValueType(vt).Value := Query.FieldByName(vt.Name).AsString;
veInteger:
TIntegerValueType(vt).Value := Query.FieldByName(vt.Name).AsInteger;
veXxxx
...
end;
end;
end;

If you have any more questions, then feel free to ask them here.

Joanna

--
Joanna Carter (TeamB)

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

0 Comments:

Post a Comment

<< Home