Thread: OO design question

  1. #1
    Cheesy Poofs! PJYelton's Avatar
    Join Date
    Sep 2002
    Location
    Boulder
    Posts
    1,728

    OO design question

    I've got a question involving the best way to design an OO problem. Say you've got an object Employee that is so massive that you decide for it to contain smaller objects (like WorkStatistics and PersonalInfo) for better manageability. Now my question is, what is better: to nest these objects inside the Employee object or to declare them in the outside interface object and include pointers that point to the employee they are referencing? I've seen both done but to me they both have their drawbacks. Like for example, if you have many nested objects its a pain to get at the lowest one from the outside world like so:
    Code:
    // I couldn't think of a better example off the top of my head! 
    // Just imagine each object being massive so as needed to be 
    // broken up
    
    string Employee::returnFavOutdoorHobby()
    {
        return myPersonalInfo.returnFavOutdoorHobby();
    }
    
    string PersonalInfo::returnFavOutdoorHobby()
    {
       return myHobbies.returnFavOutdoor();
    }
    
    string Hobbies::returnFavOutdoor()
    {
       return myOutdoor.returnFavorite();
    }
    
    string Outdoor::returnFavorite();
    {
       return Favorite;
    }
    Exagerated, but I hope you understand what I mean! But on the other hand, declared outside with pointers can be a real pain, not to mention hard to read... Anyone know how something like this is usually approached in a real world situation?

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Use a nested class if and only if you simply cannot reuse that sort of object somewhere else. Next, I don't understand where you're going with that second idea. In situations like these, a stored pointer is a bad idea UNLESS you simply MUST access Employee info through the sub-object. Either way, things can get complicated very fast...


    Code:
    class Name {
    public:
    string first;
    string middle;
    string last;
    string entire;
    //...
    string GetName(){ return entire; }
    }
    
    //...needed for the next class to be defined!
    class EmployeeBase {
    public:
    virtual string GetName();
    }
    
    class NeedPointer {
    NeedPointer(EmployeeBase *instance){
    internal = instance;
    }
    string GetName(){
    return internal->GetName();
    }
    EmployeeBase * internal;
    };
    
    
    class Employee: public EmployeeBase{
    public:
    Name name;
    NeedPointer pointer;
    Employee():pointer(this){}
    //...
    string GetName(){ return name.GetName(); }
    };

    The code for the nested version is not much better either...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Seeking motivation... endo's Avatar
    Join Date
    May 2002
    Posts
    537

    Re: OO design question

    Originally posted by PJYelton
    I've got a question involving the best way to design an OO problem. Say you've got an object Employee that is so massive that you decide for it to contain smaller objects (like WorkStatistics and PersonalInfo) for better manageability. Now my question is, what is better: to nest these objects inside the Employee object or to declare them in the outside interface object and include pointers that point to the employee they are referencing? I've seen both done but to me they both have their drawbacks. Like for example, if you have many nested objects its a pain to get at the lowest one from the outside world like so:
    Code:
    // I couldn't think of a better example off the top of my head! 
    // Just imagine each object being massive so as needed to be 
    // broken up
    
    string Employee::returnFavOutdoorHobby()
    {
        return myPersonalInfo.returnFavOutdoorHobby();
    }
    
    string PersonalInfo::returnFavOutdoorHobby()
    {
       return myHobbies.returnFavOutdoor();
    }
    
    string Hobbies::returnFavOutdoor()
    {
       return myOutdoor.returnFavorite();
    }
    
    string Outdoor::returnFavorite();
    {
       return Favorite;
    }
    Exagerated, but I hope you understand what I mean! But on the other hand, declared outside with pointers can be a real pain, not to mention hard to read... Anyone know how something like this is usually approached in a real world situation?
    Actually thats a good example of OO design. One of the things that is apparent when your looking at OO designs is that the data is spread amongst a network of different objects. Suppose he has 3 hobbies and each has a cost, to get the total cost of his hobbies you just need to cost data member of the separate Hobby objects and add them up. It does make for simpler code, but more class means things get very complicated very quickly!
    Couldn't think of anything interesting, cool or funny - sorry.

  4. #4
    Cheesy Poofs! PJYelton's Avatar
    Join Date
    Sep 2002
    Location
    Boulder
    Posts
    1,728
    Sebastiani, I understand your reasoning for not using pointers, but you also mentioned to not nest classes unless it can't be used elsewhere. I'm confused as to why not. I mean if I have a class called Hobbies, why can't this be nested in both an Employee class and say a Student class? Instead of nesting or pointers, what would you recommend? Sorry for all the questions!!

    And endo, I agree with the plusses of this type of structure, but in my example in order to get at the favorite outdoor hobby from the outside interface, you have to go through four functions. Seems very redundant to have each subclass essentially have the same function...

  5. #5
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Well, it violates true code reuse. If you decided to make a change to your hobby class - guess what? You will have to make changes to ALL the classes you pasted that code into! But is there anything wrong with using that method? Not necessarily. But not very OOP. But let's say you had a nested class that you definately would never need anywhere else. Here is an example:
    ( This nested class simply helps clean up some of the internal Employee member function code...)


    Code:
    
    class Employee {
    public:
    bool employed;
    //...
    class TheoreticallyFired {
    private:
    Employee *employee;
    public:
    TheoreticallyFired(Employee * this_employee) {
      employee = this_employee;
      if( !employee->employed ) //..already fired...
       employee = NULL;
      else
       employee->employed = false; //...simulate...
     }
    ~TheoreticallyFired() {
      if( employee != NULL )  
       employee->employed = true; //...end of simulation...
     } 
    };
    
    //...first an example of life without TheoreticallyFired...
    
    void CalculateCompensation() {
     bool simulation;
      if(employed) {
        simulation = true; 
        employed = false; //...set for simulation
        }
      else
       simulation = false;
    
    //...calculate compensation...
    
      if(simulation)
       employed = true;  //...reset...
     }
    
    //...and now with the nested class...
    
    void MoreCompensatoryCalculations() {
    
     TheoreticallyFired simulation(this);
    
     //...calculate compensation...
    
     } //..."simulation" goes out of scope here and automatically cleans up...
    };
    So the point is: this nested class has no real use outside of an employee, and so justifies itself.

    I realize your reluctance to be redundant. There are advanced techniques can cut down on this, but really, what's worse: redundancy of syntax or redundancy of code? You should be happy that all you have to do is have each class call a member function with the same signature. Very easy to implement, wasn't it?

    Finally I think you should try to avoid internal pointers and even nested classes unless you can justify them to yourself. Just use the objects as variables, and leave the delegation of most of the class specific functionality to the class itself.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  6. #6
    Cheesy Poofs! PJYelton's Avatar
    Join Date
    Sep 2002
    Location
    Boulder
    Posts
    1,728
    Oops, it looks like I wasn't very clear what I meant by nested classes, I'm sorry! I simply meant that an instance is declared within another class, not the class itself actually being declared within another class. Do you think this is not very OOP either? But you definately make some great points either way, and you're right, it's not very hard to write those extra functions even if they are redundant!

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    I simply meant that an instance is declared within another class
    ...corresponds with:

    Just use the objects as variables...
    Objects are meant to be variables. This is both common and desired...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #8
    Cheesy Poofs! PJYelton's Avatar
    Join Date
    Sep 2002
    Location
    Boulder
    Posts
    1,728
    Okay, thats what I thought and the reason I was confused until I figured out we were talking about different things! I just wasn't sure if it was desirable to have an instance of a class within an instance of a class within an instance of a class etc etc when you might need to access the farthest in class from the outside interface but you've straightened me out on that. Thanks for the help!

  9. #9
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Actually, this was the real impetus for struct's in C: the ability to use them as variables of other structs.

    struct Name {
    //...
    };

    struct Address {
    //...
    };

    struct Contact {
    struct Name name;
    struct Address address;
    };

    struct Employee {
    struct Contact info;
    struct Employment data;
    };

    int main(){

    struct Employee i;

    strcpy(i.info.name.first, "Jack");

    }


    This is how the struct promoted code reuse. Compare with the easier syntax but less reusable:

    struct Employee {
    char first[100];
    char last[100];
    //...
    char street[100];
    //...etc, etc...
    };


    Now we can do:

    strcpy(i.first, "Jack");

    ...which of course is easier, but the struct is very unsightly since it now contains maybe 40 members compared with maybe 4, as in the first example.

    So it's just a matter of taste and style, but either way, you can and should treat structs and classes as if they were native data types. And since we're on the subject, let me point out that there is no difference between a struct and a class in C++ except:
    - structs members are by default public, classes private.
    - you must use the "typedef" keyword when defining structs in order to declare them without the "struct" keyword.

    Other than that, you can have structs with member functions, and they can have constructors, etc, too.

    Still, in the C++ community, the convention is to always use classes unless the object is solely a "data container", in which case a struct may be used...
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. another exercise question
    By luigi40 in forum C# Programming
    Replies: 3
    Last Post: 11-28-2005, 03:52 PM
  2. program design question
    By Chaplin27 in forum C++ Programming
    Replies: 1
    Last Post: 06-23-2005, 07:18 PM
  3. program design question
    By Chaplin27 in forum C++ Programming
    Replies: 0
    Last Post: 06-23-2005, 06:58 PM
  4. OO Design regarding returning a value from an object
    By filler_bunny in forum C++ Programming
    Replies: 6
    Last Post: 08-24-2003, 05:57 AM
  5. design question: opinion
    By ggs in forum C Programming
    Replies: 2
    Last Post: 01-29-2003, 11:59 AM