Dynamic class inheritance

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • santiagofs
    New Member
    • Aug 2009
    • 4

    Dynamic class inheritance

    Hi, I want to know if it is any workaround for this:

    I have a class which models a database table behavior (table abstract class)
    I have several clases wich extends the table abstract class, providing information about their fields. The name of this classes are the names of the tables on the database. (users, stock, sales, etc)

    I want to have a class wich provide additional functionality to each the users, stock, sales, etc, and define it dynamically.

    Ex:
    class Users extends Table{}
    $myParent = 'Users'
    class List extends $myParent {}

    This actually doesn't work, that's why I'm looking a workaround.
    Thank you.
  • Dormilich
    Recognized Expert Expert
    • Aug 2008
    • 8694

    #2
    Originally posted by santiagofs
    I have several clases wich extends the table abstract class, providing information about their fields. The name of this classes are the names of the tables on the database. (users, stock, sales, etc)
    this doesn’t make sense to me. usually you create several instances of one class to resemble each of the tables, which would also solve your inheritance problem.

    Comment

    • santiagofs
      New Member
      • Aug 2009
      • 4

      #3
      I understand it may be not make sense to you. Lets try explain it a bit more.
      As you say, I'm creating several instances of the table class to resemble each of the tables.
      But each of this classes may be used in different contexts: managing lists and editing records on a CMS, presenting data to the user, make summarys, manage translations, etc.

      You can create a base class which do all that things, but you obtain a single huge class which is very difficult to mantain (and understand).
      Also, the idea is the table base class can be used in many projects without changes, meanwhile other behaviors do.

      It's also a more semantic approach if you want: the table abstract class and its childs belongs to the data layer.
      The dynamic classes I'm trying to implement are to present data to the users, the top layer of any application.


      (You can use interfases, but you have to write the same method on each child class. Not a solution.)

      Hope I can explain my problem a little more.

      Thanks

      Comment

      • Dormilich
        Recognized Expert Expert
        • Aug 2008
        • 8694

        #4
        Originally posted by santiagofs
        But each of this classes may be used in different contexts: managing lists and editing records on a CMS, presenting data to the user, make summarys, manage translations, etc.

        You can create a base class which do all that things, but you obtain a single huge class which is very difficult to mantain (and understand).
        I’d do a different child class (or something along) for each purpose.

        Originally posted by santiagofs
        It's also a more semantic approach if you want: the table abstract class and its childs belongs to the data layer.
        The dynamic classes I'm trying to implement are to present data to the users, the top layer of any application.
        maybe one of the standard Design Patterns may be of use here (Factory or Facade…)

        Originally posted by santiagofs
        (You can use interfaces, but you have to write the same method on each child class. Not a solution.)
        Interfaces are for API (completely different purpose), and you don’t need to limit yourself to just one child class—if it suits your needs you can have 4 or more extending classes.

        Comment

        • santiagofs
          New Member
          • Aug 2009
          • 4

          #5
          Dormilich, thanks for your replay

          Originally posted by Dormilich
          I’d do a different child class (or something along) for each purpose.
          Interfaces are for API (completely different purpose),
          I understand interfaces are a way to implement pseudo multiple inheritance. Probably I'm wrong.

          Originally posted by Dormilich
          and you don’t need to limit yourself to just one child class—if it suits your needs you can have 4 or more extending classes.
          I know you can have the child classes you want:
          Users extends List extends Edit extends Table (where List, Edit and Table are kind of abstract and Users do the overrides needed).
          But you came with a Users class having a lot of functionallity you dont need in a particular moment (you don't need List functionallity while using Edit) and most important, suponse you upgrade your model including two more clases:
          Users extends Summary extends Translations extends List extends Edit extends Table
          Then you have to modifie all the final classes (Users, Stock, Products, Blah) to suit your new needs (and all the projects you are using them)

          What I'm trying to solve (I'm carrying it through many time and different programming languages) is how to extend the functionality / behavior of particular objects, not the more abstract ones.
          Usually I used object composition but this implies modification of the base classes every time you have a new need.

          Let say both you and me are Persons (and instances of the Person class). If I go to a party I wear a Tuxedo, if I go to the beach I wear a SwimSuit.
          The exposed models are as I'm going to a party with all my wardrobe in a bag! and worst, that you and me are carring the exact same clothe everywhere.


          Originally posted by Dormilich
          maybe one of the standard Design Patterns may be of use here (Factory or Facade…) .
          Thanks, I'll read what you propose (I'm not aware about the existing theoretical patterns).

          Thanks again for replying, it helps a lot to expose a problem to get a better understanding of it.

          Comment

          • Atli
            Recognized Expert Expert
            • Nov 2006
            • 5062

            #6
            Hi.

            This looks a bit odd to me.
            As I see it, you are trying to add functionality to a class after it has been defined.

            For example, if we take your wardrobe example, it looks to me like you are trying to do something like:
            Code:
            abstract class Person { }
            
            class John extends Person {}
            class Jane extends Person {]
            
            class Tuxedo extends John {}
            class Swimsuit extends Jane {}
            Where the parents of the Tuxedo and Swimsuit classes would be dynamic, changing according to which person is meant to wear what.

            But this obviously has major issues, like the fact that using this method (which isn't possible, by the way), only one person could wear each wardrobe per execution.

            You should be doing something more like:
            Code:
            abstract class Person {}
            
            abstract class TuxedoPerson extends Person {}
            abstract class SwimsuitPerson extends Person {}
            
            class John extends TuxedoPerson {}
            class Jane extends SwimsuitPerson {}
            And PHP being awesome, you can define which class to extend at runtime:
            [code=php]
            if($wardrobe == "Tuxedo") {
            class John extends TuxedoPerson {}
            }
            else if($wardrobe == "Swimsuit") {
            class John extends SwimsuitPerson {}
            }
            else {
            class John extends Person{}
            }[/code]

            P.S.
            It's like 5 in the morning here, so I may quite possibly be to tired to even understand the problem... I'll check back in the morning (or more like tomorrow afternoon, at this rate :-)

            Comment

            • Markus
              Recognized Expert Expert
              • Jun 2007
              • 6092

              #7
              Originally posted by Atli
              Hi.

              This looks a bit odd to me.
              As I see it, you are trying to add functionality to a class after it has been defined.

              For example, if we take your wardrobe example, it looks to me like you are trying to do something like:
              Code:
              abstract class Person { }
              
              class John extends Person {}
              class Jane extends Person {]
              
              class Tuxedo extends John {}
              class Swimsuit extends Jane {}
              Where the parents of the Tuxedo and Swimsuit classes would be dynamic, changing according to which person is meant to wear what.

              But this obviously has major issues, like the fact that using this method (which isn't possible, by the way), only one person could wear each wardrobe per execution.

              You should be doing something more like:
              Code:
              abstract class Person {}
              
              abstract class TuxedoPerson extends Person {}
              abstract class SwimsuitPerson extends Person {}
              
              class John extends TuxedoPerson {}
              class Jane extends SwimsuitPerson {}
              And PHP being awesome, you can define which class to extend at runtime:
              [code=php]
              if($wardrobe == "Tuxedo") {
              class John extends TuxedoPerson {}
              }
              else if($wardrobe == "Swimsuit") {
              class John extends SwimsuitPerson {}
              }
              else {
              class John extends Person{}
              }[/code]

              P.S.
              It's like 5 in the morning here, so I may quite possibly be to tired to even understand the problem... I'll check back in the morning (or more like tomorrow afternoon, at this rate :-)
              Still, even that would make little sense to me; favor composition over inheritance! And by that I mean, prefer HAS-A over IS-A.

              Code:
              abstract class AbstractPerson {
              	
              	/**
              	 * @var string Person's name
              	 */
              	private $name;
              	/**
              	 * @var Wardrobe Person's current wardrobe
              	 */
              	private $wardrobe;
              	
              	/**
              	 * @see	   AbstractPerson::$name
              	 * @param  string $name
              	 * @return void
              	 */
              	public function setName($name) {
              		// All people will set their name the same way,
              		// so this doesn't need to be abstract
              		$this->name = $name;
              	}
              	
              	/**
              	 * @see	   AbstractPerson::$wardrobe
              	 * @param  Wardrobe $w
              	 * @return void
              	 */
              	public function setWardrobe(Wardrobe $w) {
              		// Again, this will be the same throughout any child
              		// classes, so no need to abstract it.
              		$this->wardrobe = $w;
              	}
              	
              	// I got bored of documenting.
              	public function getWardrobeType() {
              		return $this->wardrobe->getName();
              	}
              	
              	/**
              	 * Makes the person walk - behaviour defined by child classes,
              	 * because all people walk differently.
              	 * 
              	 * @access public
              	 * @return void
              	 */
              	public abstract function walk();
              	/**
              	 * Makes the person talk - behaviour defined by child classes,
              	 * because all people talk differently.
              	 * 
              	 * @access public
              	 * @return void
              	 */
              	public abstract function talk();
              }
              
              /**
               * Use a base abstract class to program to an interface,
               * not implementation - this is generally a strongly-typed
               * language technique, but PHP 5 has type-hinting, so use it!
               */
              abstract class Wardrobe {
              	
              	public $name;
              	
              	public function setName($name) {
              		$this->name = $name;
              	}
              	public function getName() {
              		return $this->name;
              	}
              }
              
              class TieAndSuit extends Wardrobe {
              	// Some cool methods would go here - I can't think of any
              	// at the moment.
              	public function __construct($name = __CLASS__) {
              		$this->name = $name;
              	}
              }
              
              class Swimsuit extends Wardrobe {
              	// Some cool methods would go here - I can't think of any
              	// at the moment.
              	public function __construct($name = __CLASS__) {
              		$this->name = $name;
              	}
              }
              
              class BaggyJeans extends Wardrobe {
              	// Some cool methods would go here - I can't think of any
              	// at the moment.
              	public function __construct($name = __CLASS__) {
              		$this->name = $name;
              	}
              }
              
              class John extends AbstractPerson {
              	
              	public function __construct($name = __CLASS__) {
              		$this->name = $name;
              	}
              	
              	/**
                   * @see AbstractPerson::talk()
                   */
                  public function talk() {
                  	// Should probably return this rather than print it
              		// directly in the method.. but whatever trevor!
                      printf("Hi, my name is %s, and I have a deep void"
              			  ." - the women love it, especially your mom.\n",
              			  $this->name
              		);
                  }
                  
                  /**
                   * @see AbstractPerson::walk()
                   */
                  public function walk() {
                      printf("Hi, my name is %s, and I walk with a gangster-lean.\n",
              			   $this->name
              		);
                  }
              }
              
              $john = new John;
              $john->walk();
              $john->talk();
              $john->setWardrobe(new BaggyJeans);
              print $john->getWardrobeType();
              Notice AbstractPerson: :$wardrobe - that is a HAS-A relationship; AbstractPerson has a Wardrobe - because AbstractPerson: :$wardrobe expects the abstract Wardrobe, you're not programming to an implementation, but to an interface (not an interface struct, but to the super-type Wardrobe).

              My $0.2

              P.S. I got bored of documenting it - that always happens to me! :P

              Comment

              • santiagofs
                New Member
                • Aug 2009
                • 4

                #8
                Atli, thank you. I didn't know you could use conditionals for class extension. I think it not applies to my current problem, but sure it will be usefull.

                Markus, I agree with you that composition must be favored over inheritance: a Person is not an Arm or a Leg, a Person Has an Arm and Has a Leg.

                But only when the HAS A really applies: a Diver could HAVE Equipment but IS a Person.

                Object composition has a backdraw too: if you add behaviors to a base class over time, again, it becames huge and difficult to mantain. In a scenario where you are not the only developer, having many people touching base classes it's always a problem.

                I came to a solution that combines a little of both concepts (inheritance and composition), thought I think it may have less performance:


                Code:
                class Dynamic_class {
                    private $base = '';
                    
                    function __construct($base)
                   {
                       $this->base = $base
                   }
                      public function __call($name, $arguments) {
                		return call_user_func_array(array($this->base, $name),$arguments);
                	}
                	
                	public function __set($name, $value) {
                       $this->base->$name = $value;
                    }
                
                    public function __get($name) {
                		return $this->base->$name;
                	}
                }
                
                class Diver extends Dynamic_class
                {
                    // Diver behavior here
                
                }
                
                class Person {}
                
                $John = new Person;
                $JohnDiver = new Diver($John);
                Through $JohnDiver you can access both Person and Diver properties and methods, and if needed, you can override in Diver any method or property of Person.

                This way you can create all the different behaviors you want (Diver, Pilot, Doctor, Blah), without directly modifying the base class (which means you can always trust on code it's actually working and properly debuged)

                All classes remains small enough to be well handled (the big issue with multiple inheritance)
                You can have each developer on a team working on a different behavior at the same time without interfering with others.

                Besides, as the solution I came is not as 'elegant' I'd like, I think it helps a lot the abstraction process and modeling.

                Thank you Marcus, it was by talking with you I came to this approach. I you see any problem with it or a way to do it better, please tell me.

                Thanks again.

                Comment

                Working...