Board index » delphi » My first object!

My first object!


2006-06-04 04:23:35 PM
delphi43
I have posted in the attachment ng. Look for the title "My first object".
The attached person.pas has some questions in it that are marked as
"Q's:".
I am asking for constructive options from others that know more than I do.
This started out as a simple just messing around thing and then just
kept going and going and going. So there is no standard structure to it
since it is Rambo coded. At this point due to where it is going, I am
going to take a step back and work on the structure before moving
forward with this. I have decided that I will use it in my next
application.
I have thought about taking the TAddress and TPhone and making them
collections rather than an array. I just don't know which would be
better and more simplistic.
I know the syntax is correct cause it does not cause any errors when
compiled (I have it opened in an application). But I have not checked
the logic part of it out yet.
Thanks to every one for the help. I am looking forward to your comments
and suggestions.
Just learning the objects of work.
BMitchell
 
 

Re:My first object!

"BMitchell" <XXXX@XXXXX.COM>a écrit dans le message de news:
XXXX@XXXXX.COM...
| I am asking for constructive options from others that know more than I do.
Comments inline...
| I have thought about taking the TAddress and TPhone and making them
| collections rather than an array. I just don't know which would be
| better and more simplistic.
You are always best using a wrapper class around TObjectList as this then
provides typesafe, variable size collections.
| TTitleName = //Standard greating or title for a persons name
| (tnNone, tnMr, tnMiss, tnMrs, tnDr);
|
| TSufixName = //Standard name sufixes
| (snNone, snJr, snSr, snEsq, snII, snIII);
You really shouldn't need enumerations for what are essentially string
values. It would be better to allow the user to simply enter the title or
suffix as you can never cover all available options; titles like Prof., Mme,
etc or suffixes like BSc, FRPS, or multiples thereof will break your rule.
| TNameFormat = //What format to return the name string in
| (
| nfLastFirst, // LastName, FirstName MiddleInt
| nfFirstLast, // FirstName MiddleInt LastName
| nfFull // Title. FirstName MiddleName LastName Sufix.
| );
This isn't really a business rule, it is more a presentational rule and
should reside in a UI related class.
| // Create name
| TPersonName = class(TObject)
| private
| FTitle: TTitleName;
| FFirstName: string;
| FMiddleName: string;
| FLastName: string;
| FSufix: TSufixName;
| function GetFixName(ptype: PTypeInfo; pIndex: Integer; pPrefix:
integer): string;
| public
| property NameTitle: TTitleName read FTitle write FTitle default
tnNone;
| property NameSufix: TSufixName read FSufix write FSufix;
| procedure SetName(pFirstName, pMiddleName, pLastName: string);
overload;
| procedure SetName(pName: string); overload;
| procedure SetName(pFirstName, pLastName: string); overload;
| function GetName: string;
| end;
Likewise, I'd tend to make the parts of a name simply properties within
the Person class; this TPersonName class seems to me to be over-engineering
| // Create phone
| TPhone = class(TObject)
| {Q's: How to display a dialog to ask for phone input with all the options
needed
| and do it from here. The calling object would just call
TPhone.NewNumber}
You do not add UI functionality in a business object class, this goes in the
UI layer.
| private
| FForiegn: boolean;
| FAreaCode: string;
| FCityCode: string;
| FNumber: string;
| FExtension: string;
| FPhoneType: TPhoneType;
|
| public
| property IsForiegnNumber: boolean read FForiegn write FForiegn
default False;
| property AreaCode: string read FAreaCode write FAreaCode;
| property PhoneExtensionIs: string read FExtension write FExtension;
| procedure PhoneNumber(pNumber: string);
| //function GetFullNumber(pFormat: TPhoneFormat): string;
| //procedure NewNumber;
| end;
You need to consider that some foreign formats don't separate out into three
sections like you have assumed; French numbers look like 09 99 99 99 99. I
wouold suggest you only have one string property for the complete number and
then allow derived classes from TPhone to override a formatting function.
| // Create SSN
| TSocialSecurityNumber = class(TObject)
| private
| FFirstThree: integer;
| FSecondTwo: integer;
| FLastFour: integer;
| function GetSSN: string;
| procedure SetSSN(const Value: string);
| public
| property SSN: string read GetSSN write SetSSN;
| end;
Same applies for SSNs for foreign countries as for phones.
| // Create Address
| {Q's: I'd like to do TAddress.AddNewAddress and a dialog box open and
allow
| the user to enter data for the new address object. How would this be
done
| and still maintain proper OOP?}
You would not normally use static (class) methods to add items to a list of
objects; it is better to create typesafe collection classes. The showing of
dialogs should not be instigated from within business object classes, but
from within the UI framework.
| TAddress = class(TObject)
| private
| FAdressType: TAddressType;
| FNumber: string;
| FStreetName: string;
| FAptNumber: string;
| FState: string;
| FCity: string;
| FCountry: string;
| FCounty_Prov: string;
| public
| //Add properties for each field
| end;
|
| {Q's: How do I add properties for FPhone, FSSN, and FAddress? How do the
calling
| objects get to those?}
Just the same as you would with any other type; just remember to create an
instance of each in the constructor of the containing class for thos fields
that are not allowed to be nil.
| {Q's: Should I use arrays for TPhone and TAddress? There could be more
than one}
No, use typesafe wrapper collections using TObjectList
| // Create person
| TPerson = class(TPersonName)
| private //Should phone and address arrays or collections
| FPhone: array of TPhone;
| FSSN: TSocialSecurityNumber;
| FAddress: array of TAddress;
| FDateOfBirth: TDateTime;
| public
| constructor Create;
| procedure AddNewAddress;
| end;
The AddNewAddress procedure would not be necessary as the Addresses
property, if it used a typesafe collection would have an Add method.
| function stripToNumbers(pStr: string): string;
A completely OO application should never have procedures in the units, this
kind of functionality would best be a private method of the class in which
it is called.
| procedure TPhone.PhoneNumber(pNumber: string);
...
| if StrLength < 10 then
| begin
| MessageDlg('Phone number entered is invalid. Please ensure the area
code '
| +#13+#10+'is included.', mtWarning, [mbOK], 0);
| Exit;
| end;
Don't do validation that requires user interaction, inside the business
class, this should either happen post-entry in the case of populating
objects in code, or in a separate validation class when entered from a UI.
| procedure TPersonName.SetName(pFirstName, pMiddleName, pLastName: string);
Not a good idea to require multiple parts of a name in one procedure call,
rather use a formatting function in an "AsString()" function.
| HoldName := HoldName + Trim(FFirstName);
| HoldName := HoldName + Trim(FMiddleName);
| HoldName := HoldName + Trim(FLastName);
by the time the constituent part fields are populated, they should already
be trimmed.
My overall opinion of your brave attempt is that you have overdone the
engineering on this one :-)
Let us see what you make of these comments.
Joanna
--
Joanna Carter [TeamB]
Consultant Software Engineer
 

Re:My first object!

Quote
| TSufixName = //Standard name sufixes
| (snNone, snJr, snSr, snEsq, snII, snIII);

You really shouldn't need enumerations for what are essentially string
values
I agree. You would typically use an enumeration when the values are
A) The system only accespts certain values, no user specified option is
allowed
B) If the system needs to understand the values so that it may act
differently depending on what is set. For example a gender "Male" may
restrict this person from being specified as somebody's mother, but not
their father.
 

Re:My first object!

BMitchell writes:
Ok.. I get the idea that sucked really hard.
Let me know where I am thinking RAD and OO. This would help me make the
transition.
In using RAD, I'd take something like a frame and place all the
functions into the frame that would be needed for a specific operation,
from the UI to the business validation and datasets all within one
wrapper, I could make one call and have all the functionality I needed
with out any extra coding and use it in multiple places as needed. It
seems that I can't do this in OOP.
Let me know if I have this correct:
The BO should only handle metadata and should only raise exceptions when
there are errors in the metadata.
The UI should be responsible for catching the exceptions raised by the
BO and handling any message displays.
Where does the Presentation layer come into play for exceptions?
I should not be able to just call up a frame (as an example), work with
its abilities and let it go. This seems to break every rule of OOP from
what I have read here. Is this correct? I wouldn't be able to use it in
another project without some rewriting. I don't see where the reuse
comes into play at this point. I can see reuse as far as the object goes
but beyond that I am lost.
Quote
You are always best using a wrapper class around TObjectList as this then
provides typesafe, variable size collections.
I checked into TObjectList and like what I saw. Looks like most of the
processes with adding and deleting objects are right there.
Quote
You really shouldn't need enumerations for what are essentially string
values. It would be better to allow the user to simply enter the title or
suffix as you can never cover all available options; titles like Prof., Mme,
etc or suffixes like BSc, FRPS, or multiples thereof will break your rule.
I can see that, I will remove all of the enumerations and just make them
fields with properties for the user to just enter text.
Quote
You need to consider that some foreign formats don't separate out into three
sections like you have assumed; French numbers look like 09 99 99 99 99. I
wouold suggest you only have one string property for the complete number and
then allow derived classes from TPhone to override a formatting function.
So I'd do TPhone that is basically just a single field to hold the
phone number, then using this as the base class create TFrenchPhone,
TUSPhone etc. Each one would then implement its own phone number format.
This same idea would also go for the TSocialSecurityNumber. Did I get
that correct?
Quote
You would not normally use static (class) methods to add items to a list of
objects; it is better to create typesafe collection classes. The showing of
dialogs should not be instigated from within business object classes, but
from within the UI framework.
I have found when using DA-Grids, they have a tendency to cause issues
with saving empty records, not saving when I need them to and so on.
What I have started doing is creating a data entry TFrame with all the
fields needed for data entry. If I use the TPerson class. How do I make
it so that this frame or dialog box is always used with out adding extra
steps in the process?
If I place the data entry dialog into the UI, then I'd loose the
ability to know that I can call that dialog to do the entry without
going out to code it back in. If this makes sense.
Quote
| function stripToNumbers(pStr: string): string;

A completely OO application should never have procedures in the units, this
kind of functionality would best be a private method of the class in which
it is called.
What do I do with functions and procedures that can be used across
multiple objects? I don't want to put a copy in each one do I?
Quote
Don't do validation that requires user interaction, inside the business
class, this should either happen post-entry in the case of populating
objects in code, or in a separate validation class when entered from a UI.
When the BO finds an issue with the data. How do I let the user know
there is an issue? Would the object call back to the interface layer
telling the UI that there is an issue to be dealt with? This would be
like raising an exception. Let the UI handle the error to the user?
Quote
Not a good idea to require multiple parts of a name in one procedure call,
rather use a formatting function in an "AsString()" function.
How would I use the AsString() function?
Thank you to every one for the help.
Just bare with me as I figure this out.
Just learning the objects of work.
Billy
 

Re:My first object!

Quote
It seems that I can't do this in OOP.
If not for OOP you wouldn't have been able to do that in the first place :-)
OOP <>OPF. There is much more to OO programming and design than using an OPF.
However, once you start using OO properly you usually run into the problem of
persisting your objects, hence the need for an OPF.
The trouble with your frame approach (and with RAD-based programming in general)
is that everything is mushed in together. You have UI, business logic and data
access all tightly coupled together. This means your code will be more difficult
to read and maintain than is necessary.
A better idea is to layer everything so that different bits know as little as
possible about each other (eg ideally data access should know nothing about UI,
and vice versa).
Your code becomes easier to read, and modifications are less risky because the
implications of changes are localised.
You can still have complex code hiding behind a simple interface (this is called
the Facade pattern).
Cheers,
Jim Cooper
_____________________________________________
Jim Cooper XXXX@XXXXX.COM
Skype : jim.cooper
Tabdee Ltd www.tabdee.ltd.uk
TurboSync - Connecting Delphi to your Palm
_____________________________________________
 

Re:My first object!

So basically I'd use the layer approach in my frame as in: TLogin -
Presentation - UI. The TLogin would also have access to the OPF for
access to the database for verification of the login. But from the UI
layer it is just using a login in frame. Does that sound right?
B_Mitchell
 

Re:My first object!

Quote
Does that sound right?
Sounds better, yes :-)
I'm doubtful myself of the wisdom of using a frame for everything still, since
many of these things don't need to be components, just classes. But it is a
start, and it is easier and better to take smaller steps, IMO.
Cheers,
Jim Cooper
_____________________________________________
Jim Cooper XXXX@XXXXX.COM
Skype : jim.cooper
Tabdee Ltd www.tabdee.ltd.uk
TurboSync - Connecting Delphi to your Palm
_____________________________________________