Vuud has asked for the wisdom of the Perl Monks concerning the following question:
I am creating a series of objects which will persist to a SQL database. The question comes into play with how I should design these objects.
Right now I have a PERSON object which has all kinds of basic info (name, address, etc). Then I took this object and used it as a base class for an EMPLOYEE object (adds SSN, Title, etc).
This works fine, but here is where I lost it. I have a few more types to add and lets say I have a CUSTOMER who is also a VENDOR. So I want this entity to have the properties and functions of PERSON, VENDOR and CUSTOMER.
The only thing I can think of is to make PERSON inheret the other two... Each object supports its own Save method which will persist its data to the correct tables in the database.
So from the code I need to be able to create a new person and tell it what types they are (EMPLOYEE, VENDOR, etc)
Any advice would be greatly appreciated.
Vuud
"I'm never going to work another day in my life. The Gods told me to relax... I'm gonna be hooked up right"
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
(tye)Re: Objects in PERL
by tye (Sage) on Aug 25, 2001 at 09:27 UTC | |
Gee, this sounds just like nearly every book I've read about OO design. It also is not at all how I've seen OO design done well. Books that teach OO design have to cover some basic topics. One of the big ones is inheritance. This means that authors of OO books end up asking themselves the question "What should we design that will teach about inheritance". And when many read their books, they come away thinking that the first step when designing objects is "How should I use inheritance in this design?". Both my experience with OO design and some of the better books on OO design that I've read indicate that you shouldn't be thinking much about inheritance at all when you start a project, except perhaps to think "I won't use inheritance unless the need for it becomes clear and obvious". The best and most common use of inheritance is a simple inheritance of interface. This is like prototyping a subroutine except that you end up prototyping a whole class of subroutines (methods). But Perl doesn't support prototyping of subroutines (Perl has subroutine prototypes but they aren't well suited for using to prototype subroutines, despite the name) and Perl's OO doesn't support inheritance of interface. There are some modules you can use that tack on one sort or another of inheritance of interface, but this isn't built into Perl. Another type of inheritance is inheritance of member variables. Perl doesn't really support that either. The only type of inheritance that Perl supports in inheritance of implementation. And, although some OO books will claim that inheritance of implementation is one of the major advantages of OO because it promotes code reuse, the people I know who have done a lot of real work with OO (mostly in C++, just in case you think I'm talking about Scheme or some real OO language, which I'm not), think that inheritance of implementation is one of the worst ways you can do code reuse. Inheritance (as you've surely read) defines an "is a" relationship. And if A "is a" B, then they are very, very tightly bound together. It is much better to reuse your code via a looser bond. Perl supports a ton of these. For OO code, the common tool is "aggregation" (also called "composition" and several other names) which represents a "has a" relationship. Other methods of code reuse that fit well with Perl and can be used with OO (but that aren't OO techniques) include importing/exporting functions and tons of (other) tricks with code references and closures. Also, OO books tend to create objects like PERSON and DOG. You aren't going to make an object that captures enough functionality that is deserves to be called "PERSON". People have favorite colors, food alergies, height/weight, etc. Although you might decide that CUSTOMER is a PERSON and that EMPLOYEE is a PERSON, you are going to track very different information about EMPLOYEE vs. CUSTOMER. Now, there may be some information that you track about both, but that information isn't well described by "PERSON". I'd be more likely to have a CONTACT object which has things that I need to know about a person that I'm going to contact (name, title, address, phone). So I certainly wouldn't have VENDOR is a PERSON. I'd have a VENDOR has some CONTACTs. Now, even that may not be worth the effort. Perhaps you should just have a VENDOR and a CUSTOMER and not try to abstract out shared things. I mean, if the only code that you are going to end up sharing is a few 2-line accessor methods like getAddress() and setAddress(), then I don't think the complexity of trying to share bits of the design will be a net win. - tye (but my friends call me "Tye") | [reply] |
by Corion (Patriarch) on Aug 25, 2001 at 19:44 UTC | |
In addition, a really good book is the Design Patterns book by the gang of four. In this great book, they discuss how to do many tasks in programming while avoiding inheritance and/or modification of existing code while extending the functionality. Anybody who is interested in object oriented programming should take a look at this, whether his language of choice has single or multiple inheritance (being able to read C++ and Smalltalk helps though). The book is not for people who want to learn how to do object-oriented analysis and how to arrive at a good object model - the book only discusses how you can solve certain small tasks by applying a pattern/an idiom. Whether an object-oriented approach is fitting at all is a second question, of course. | [reply] |
by mugwumpjism (Hermit) on Aug 26, 2001 at 06:50 UTC | |
For OO code, the common tool is "aggregation" (also called "composition" and several other names) which represents a "has a" relationship. Just to nitpick, composition and aggregation are subtly different; composition indicates a one to one mapping, and aggregation a one to many mapping. The generic term for them is an assosiation, and if that association itself has attributes then one builds an association class to encapsulate them. | [reply] |
|
Re (tilly) 1: Objects in PERL
by tilly (Archbishop) on Aug 25, 2001 at 19:34 UTC | |
However I have one point he missed. You talk a lot about what you are going to do. You will store objects in a database. You will have these amazing general objects as soon as you figure out how to design them. And so on. But you haven't said why you are doing it. What is your actual task? What do you need to do? Have you tried thinking how to design an actual application and then walked through on paper how it would function? A good exercise is to have a group of people stand around with a ball. Each person is an object, and they throw the ball around as they call methods on each other. Have you tried that? My point is that in the abstract we tend to build castles in the sky and get into binds. A good antidote for this is to attempt to experience the practical details as directly as possible. Based on how vague and general your classes currently look, I suspect you may need some of this antidote... | [reply] |
|
Re: Objects in PERL
by Masem (Monsignor) on Aug 25, 2001 at 07:29 UTC | |
One possible adjustment for this is to keep your PERSON class, but instead of subclassing it, create an OCCUPATION (or a different term to represent 'relationship to your program' without using RELATIONSHIP) base class; PERSON would then have as an object member a one-to-many array of OCCUPATIONs. Your VENDOR, CUSTOMER, and EMPLOYEE classes then subclass from OCCUPATION. *subject to one's personal interpretation of the matter; some people believe multiple inheritence is a work of pure evil, some believe it's manna. I'm of the opinion that if you believe the only solution is multiple inheritence, you've got something wrong in your object model.
-----------------------------------------------------
| [reply] |
by Vuud (Novice) on Aug 25, 2001 at 07:57 UTC | |
I thought the multiple would be good to do. I guess I will try it the other way Thanks for the help! "I'm never going to work another day in my life. The Gods told me to relax... I'm gonna be hooked up right" | [reply] |
by Masem (Monsignor) on Aug 25, 2001 at 15:28 UTC | |
The only reason I'd define some OCCUPATION class is that while perl is not strongly typed, this allows you to check to make sure that a 'addOccupation' works right, and that you have some expected functions in which you can use in a call such as 'queryOccupations' in the PERSON class. The base class can be as simple as simply having a name of the occupation and a method to get it.
-----------------------------------------------------
| [reply] |
by mugwumpjism (Hermit) on Aug 26, 2001 at 06:43 UTC | |
At that point they are not that complicated, so I dont think creating an OCCUPATION class to subclass off of would be necesary. This is called using a Servant class, ie having one classes' attributes and members thrown into the master class, even though they should be in a seperate object. Generally it's best to avoid this, all you save is a little bit of performance at the expense of breaking your encapsulation. | [reply] |
|
Re: Objects in PERL
by mugwumpjism (Hermit) on Aug 26, 2001 at 06:36 UTC | |
Take your PERSON class and give it an attribute called ROLES, which is an unordered set (OO term: aggregation) of ROLEs. Derive CUSTOMER, EMPLOYEE, etc from ROLE. ROLE is an abstract or virtual base class. For your persistence, I really recommend you useTangram; it really is the best OO persistence tool I've seen for Perl so far. You might also want to check out my Tao::Object cass, which lets you merely define the fields of an object you wish to stay persistent, and then you get automatic attribute accessors, constructors and the like. Forget coding individual Save methods for objects, that's for monkeys! So, using Tao::Object, you might implement this as follows (except, of course, you'd be using strict etc):
| [reply] [d/l] [select] |