OOP clarification

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • fjm
    Contributor
    • May 2007
    • 348

    OOP clarification

    Hey everyone. I'm back in search of a better understanding of OOP. I feel like these past couple of months have paid off for me because I am at a point where I am really beginning to understand how this all works. I'd like to get some clarification on a few things first.

    My questions stem from wanting to use private members and methods. I know that there is a reason for making methods and members public and private and honestly I'm still not totally clear as to when to use one over the other. I have been refactoring some of old classes and in looking at them, I was mortified. I figured that when I was redoing them that I should try and stick with private members and methods where possible because that's a good thing I guess.

    I had download an app a while back that used 5 classes. Each class was like 1500 lines or so and the code looked clean to me. I figured that was a good way to program. I started to do the same thing but after looking over some of my classes, I quickly noticed that my classes were nothing more than functions instead of objects.

    In refactoring this code, I separated out the methods that required functionality inside the class and set my constructor to call a main method that would do what was needed and then return out the values I needed. I just want to make certain that I understand correctly before I continue any further.

    If I have a class like so:

    Code:
    class Hello{
        public  $out;
        private $text;
    
        public function __construct($text)
        {
            $this->text = $text;
            $this->sayHello();
        }
    
        private function sayHello()
        {
            $text = $this->text;
            $var = 'Hello, my name is: ' . $text;
            return $this->out = $var;
        }
    }
    
    $hello = new Hello('Tom');
    echo $hello->out;
    To me, this seems like the correct way to write a class. I am returning out the values that I want. The way I was doing it in the past was to call the method directly and didn’t seem right.

    Does this look correct? I have a few more questions but I'll wait on those for now to see what the feedback is on this. I'll also show you how I was doing before.

    Thank!

    Frank
  • Dormilich
    Recognized Expert Expert
    • Aug 2008
    • 8694

    #2
    I wouldn't have named the method "sayHello" because it's not 'saying' (aka printing/outputting) anything, but generally it's right. personally, I don't see the necessity of every method having a return value (esp. when you have printing methods) though if possible I let it return true/false.

    on the other hand, you're not using the return value…

    some simplifications I'd make
    Code:
    class Hello
    {
        public  $out;
        private $text;
     
        public function __construct($text)
        {
            $this->text = $text;
            $this->out = $this->sayHello();
            // $this->sayHello();
        }
     
        private function sayHello()
        {
            return 'Hello, my name is: ' . $this->text;
            // $this->out = 'Hello, my name is: ' . $this->text;
        }
    }
    for this simple class there could even be more improvements, like omitting Hello->out and using sayHello() or even __toString() for output

    Comment

    • fjm
      Contributor
      • May 2007
      • 348

      #3
      Originally posted by Dormilich
      for this simple class there could even be more improvements, like omitting Hello->out and using sayHello() or even __toString() for output
      Ok, I understand that. Thanks. :)

      In your example where you said that you would shorten it to sayHello(), isn't this acting more like a simple function than a class? This was the way that I was using it before. Because I had so many of these types of methods in a single class and would call them directly, I couldn't keep the methods private.

      I know that in your example you are using the constructor to call the sayHello method but what if you have more than 1 or even 10 of these type of methods that require one or two variables? What do you do? How do you call them?

      $foo = new MyClass();
      echo $foo->myMethod($var) ;

      My example above requires that the myMethod() method remain public. Is this not a big deal? Also, say that I have 20 of these exact type of methods in the class that each expect one or two variables passed. It seems to me that if I am passing variables directly into the methods that I should forgo the class and just use a function. No? I don't see the difference or the advantage in using your sayHello() example over a simple function.

      Thanks for the help Dormi. :)

      Comment

      • Dormilich
        Recognized Expert Expert
        • Aug 2008
        • 8694

        #4
        Originally posted by fjm
        In your example where you said that you would shorten it to sayHello(), isn't this acting more like a simple function than a class?
        well, yea, but do you want to handle any output through properties? (that may work for 1 or 2, but what about undefined/several different outputs?)

        Originally posted by fjm
        Because I had so many of these types of methods in a single class and would call them directly, I couldn't keep the methods private.
        methods are not supposed to be solely private, what use would the object then have (and what use would the interface have)?

        private methods are good, if you need tasks done that shouldn't be initialized from the outside (like e.g. connecting to a database or loading a configuration)

        Originally posted by fjm
        I know that in your example you are using the constructor to call the sayHello method but what if you have more than 1 or even 10 of these type of methods that require one or two variables? What do you do? How do you call them?
        ???

        Originally posted by fjm
        Code:
        $foo = new MyClass();
        echo $foo->myMethod($var);
        My example above requires that the myMethod() method remain public. Is this not a big deal?
        no

        Originally posted by fjm
        Also, say that I have 20 of these exact type of methods in the class that each expect one or two variables passed. It seems to me that if I am passing variables directly into the methods that I should forgo the class and just use a function. No? I don't see the difference or the advantage in using your sayHello() example over a simple function.
        not every method expects a variable input, often you can use the properties to pass around variables.

        in fact your example could be handled better by a function. but there are situations, where objects are better. I can think of writing an batch mail where the email addresses are stored in a DB.

        OOP is more than using private methods. you also have (to name some):
        - data encapsulation (prevents globals running wild)
        - inheritance (share code, re-usable)
        - patterns for common tasks (e.g. Singleton, Observer, Factory)
        - magic methods (kind of event handling)

        Comment

        • Atli
          Recognized Expert Expert
          • Nov 2006
          • 5062

          #5
          Hi.

          A couple of things I'd like to comment on...

          First.
          I think your assumption that methods should preferably be private is not really correct.

          Private members are only accessible from within the class itself, so any functionality or data you want accessible from the outside should (obviously) not be made private.
          Private members should complement the public once, but never be a requirement. Ideally, you should be able to inline ALL private functions into the public functions without having to change how the outside code uses the class.

          It's best to design classes in a way that allows you to redesign the entire interior of the class without having to change the publicly declared functions and variables. (Check out interfaces to see what I mean)

          Second.
          The way in which you designed your example class is very odd, really.
          It has no public functions, which basically just makes it a complex array with a constructor.

          Objects are meant to be more than just a collection of variables or a collection of anonymous functions. Arrays and normal functions work fine for that.

          Class members should work together.
          Public members being the controllers; the way the outside interacts with it.
          Private members providing functionality for the public functions; the internal mechanism that the outside doesn't need to be bothered with.

          Consider this alteration to your original example:
          (Sorry about the doc blocks... can't seem to not add them :P)
          (Edit... turns out I could :D)
          [code=php]
          <?php
          class Hello {
          private $name;
          private $language;

          public function __construct($na me, $language="enUS ") {
          $this->name = $name;
          $this->language = $language;
          }

          public function sayHello() {
          echo "<h3>", $this->createHello( ), "</h3>";
          }

          public function getHello() {
          return "<h3>". $this->createHello( ) ."</h3>";
          }

          private function createHello() {
          if($this->language == "isIS") {
          return "HallĂ³, Ă©g heiti {$this->name}.";
          }
          else { // Defaults to enUS
          return "Hello, my name is {$this->name}.";
          }

          }
          }

          // Say it in english
          $eng = new Hello('Tom');
          $ice = new Hello('Atli', 'isIS');

          $eng ->sayHello();
          echo "<center>", $ice->getHello(), "</center>";
          ?>[/code]
          I've implemented both a "sayHello" and a "getHello" function, both using the "createHell o" function to provide the message.

          As the "createHell o" function was only ever meant to be used by the other class functions, it is made private; inaccessible to the outside.
          The other two, meant to provide functionality to outsiders, are public.

          I've also added the ability to change languages of the message.
          The "createHell o" function is the only function that is actually aware there is a language choice (besides the constructor), but because of the cooperation between the functions, the effect is shared between them.

          This also means that if I ever need to change the message, I only ever need to change it in one place.
          Likewise, if I ever need to change the way the hello message is printed, that is in one place, rather than scattered all over your outside code, as it would have been with your example.

          Do you see what I'm trying to say?

          Comment

          • fjm
            Contributor
            • May 2007
            • 348

            #6
            Originally posted by Dormilich
            well, yea, but do you want to handle any output through properties? (that may work for 1 or 2, but what about undefined/several different outputs?)
            Is this not acceptable?

            Originally Posted by fjm
            I know that in your example you are using the constructor to call the sayHello method but what if you have more than 1 or even 10 of these type of methods that require one or two variables? What do you do? How do you call them?
            I am under the impression that each class should have a single function (and not in the literal sense). Let me give you an example. I have a class with two methods. The first method gets data from a database then internally passes the values to the second method where the data is checked then returned to the main script. In the constructor, I call the first method which starts the process. My thoughts are that the class should only do one thing. You can feed it the var(s) and it returns what you need.

            Code:
            class Hello{
                public  $out;
                private $text;
            
                public function __construct($text)
                {
                    $this->text = $text;
                    $this->sayHello();
                }
            
                private function sayHello()
                {
                    $text = $this->text;
                    $var = 'Hello, my name is: ' . $text;
                    return $this->out = $var;
                }
                
                public function doSomething()
                {
                    $val = 'Do something here';
                    return $val;
                }
            }
            
            $hello = new Hello('Tom');
            echo $hello->out;
            In my original example, I added a doSomething method. Let's just say that this class was for nothing more than to say hello. I know that it isn't useful and I could come up with a better example but it conveys my point I think.

            So, with this new public method, say that I wanted to call that method. I first have to create an instance but the constructor is looking for a var that has nothing to do with this doSomething method. How would I work this? Do you see what I mean?

            private methods are good, if you need tasks done that shouldn't be initialized from the outside (like e.g. connecting to a database or loading a configuration)
            Yes, I am seeing exactly what you mean. A good example of this would be a login script where the users' password should be made private.

            Comment

            • fjm
              Contributor
              • May 2007
              • 348

              #7
              Heya Atli. I'm glad that you joined in to help. :)

              Originally posted by Atli
              I think your assumption that methods should preferably be private is not really correct.
              OK. I understand this acutally. I was just thinking that maybe it would be better to make methods private where possible for added security but I see that isn't always a good thing or even realistic especially after seeing your example.

              Originally posted by Atli
              Private members should complement the public once, but never be a requirement. Ideally, you should be able to inline ALL private functions into the public functions without having to change how the outside code uses the class.
              OK, I understand that. I guess my question is what if a public method really has nothing to do with any of the other methods? Let's say that you have several methods that just draw data from the database and the sql requires a var for the WHERE statement. We would have to pass that variable into the method. I guess what I am trying to say here is that I am not seeing much difference between a regular function and a public method where the public methods sole purpose in life is to return data from a database. Now, if that public function actually called a private function for something, I could see it. Am I wrong? Thanks for the link on interfaces, I will check that out.


              Originally posted by Atli
              The way in which you designed your example class is very odd, really. It has no public functions, which basically just makes it a complex array with a constructor.
              OK. This goes back to what I was saying about the constructor. Instead of using a public method to do this, I thought the constructor was supposed to handle this which was why I designed it that way.

              Originally posted by Atli
              Class members should work together. Public members being the controllers; the way the outside interacts with it. Private members providing functionality for the public functions; the internal mechanism that the outside doesn't need to be bothered with.
              If I'm understanding you right, you're saying that instead of using the constructor to interact with the private methods, I should be using public functions. Yes?

              I think that maybe your example is even better than mine because it illistrates my point even better. In your example, if you wanted to use another public method that has NOTHING AT ALL to do with any of the other methods, what do you do? Do you make another class for it? Say for example that you wanted to have another function that said goodbye but instead of using the person's first name, you would be required to use their last name. I know, I know... it's a really dumb example but it makes the point. :) Would you use a new class for this or use this same class?

              I understand what you are saying, more so now then ever before. That's why I'm nitpicking here. I'm honestly getting this for a change. :)

              Comment

              • fjm
                Contributor
                • May 2007
                • 348

                #8
                Atli,

                I have been doing a bit more reading on this and have looked over the link on interface. Not certain exactly how that would help me out just yet but of course it's because I don't fully inderstand it yet. I will re-read it and look for some additional info on that.

                Regarding post #5, in your example... Your private method acts as a mutator and the public getHello acts as an accessor, right?

                Could we say that by having a mutator and accessor that we are encapsulating the data within the class? That's what it looks like to me. Am I right?

                Comment

                • Dormilich
                  Recognized Expert Expert
                  • Aug 2008
                  • 8694

                  #9
                  Originally posted by fjm
                  I have been doing a bit more reading on this and have looked over the link on interface. Not certain exactly how that would help me out just yet but of course it's because I don't fully inderstand it yet.
                  interfaces are a way for an outside developer to use your classes (think of the interface as API). conforming to an interface lets you use a class, without knowing the (internal) structure of this class.

                  when implementing an interface in a class definition, you make sure, that the required functionality is given (otherwise there will be an error).

                  an example may be found here

                  interfaces can also be used to check if an object has a (set of) public method you want to use later. (esp. when there are user defined classes involved)

                  (Atli can probably descibe that better…)

                  Comment

                  • Atli
                    Recognized Expert Expert
                    • Nov 2006
                    • 5062

                    #10
                    Originally posted by fjm
                    OK, I understand that. I guess my question is what if a public method really has nothing to do with any of the other methods? Let's say that you have several methods that just draw data from the database and the sql requires a var for the WHERE statement. We would have to pass that variable into the method. I guess what I am trying to say here is that I am not seeing much difference between a regular function and a public method where the public methods sole purpose in life is to return data from a database. Now, if that public function actually called a private function for something, I could see it. Am I wrong?
                    Depends on how you look at it, and might well be a matter of personal preference.

                    Would the function be using any class variables?
                    Would it even be related to the class itself?

                    If both are false, then this function might indeed not belong to that class, but rather by itself or in a different class.
                    If only the second one is true, the you should consider making it a static method. (A method available even without creating an instance of the class.)

                    Like, say, in a classic animal class:
                    • A method "speak" would be specific to an instance of the class, using the members for that instance. Clearly belongs to the class.
                    • A method "getAllByTy pe" would not be specific to an instance, nor related in any way to any of the other members or methods. It should, however, belong to the animal class, as it does provide functionality relating to the class. (A perfect example of a static method.)
                    • A method "setUpAminalDat abase", despite being somewhat related to the Animal class, provides no real functionality for the class itself. It should really belong to a separate, more database related, class... or just in a solo function somewhere.


                    I would imagine structuring a Animal class somewhat like:
                    [code=php]
                    class Animal {
                    /** Members **/
                    private $type;
                    private $name;

                    /** Constructors / Destructors **/
                    public function __construct($ty pe, $name, $insert=false){
                    $this->type = $type;
                    $this->name = $name;
                    if($insert) {
                    $this->addToDatabase( );
                    }
                    }

                    /** Instance methods **/
                    public function speak() {
                    echo ucfirst($this->getSound()), ", my name is {$this->name}, the {$this->type}. <br>\n";
                    }

                    private function getSound() {
                    switch($this->type)
                    {
                    default: return "yum yum"; break; // Couldn't think of anything else :P
                    case "dog": return "woof woof"; break;
                    case "cat": return "meow"; break;
                    }
                    }

                    public function addToDatabase() {
                    $sql = "INSERT INTO animals(name, type) VALUES('{$this->name}', '{$this->type}')";
                    return @mysql_query($s ql) == true;
                    }

                    /** Static methods **/
                    public static function getAllByType($t ype="dog") {
                    $sql = "SELECT name FROM animals WHERE type = '{$type}'";
                    if($result = @mysql_query($s ql)) {
                    $output = array();
                    while($row = mysql_fetch_ass oc($result)) {
                    $output[] = new Animal($type, $row['name']);
                    }
                    return $output;
                    }
                    else {
                    return array();
                    }
                    }
                    }
                    ?>[/code]
                    To be used like:
                    [code=php]<?php
                    // Create a dog and a whale
                    $cat = new Animal("cat", "Michell"); // Not added to the DB
                    $whale = new Animal("whale", "Bob", true); // Added to the DB

                    // Get all dogs already in the database
                    $dogs = Animal::getAllB yType("dog");

                    // Make em all speak
                    foreach($dogs as $_dog) {
                    $_dog->speak();
                    }
                    $cat->speak();
                    $whale->speak();
                    ?>[/code]
                    The method "getAllByTy pe" there being a key part of the class, despite the fact that it is detached from the rest of it, and that it only really performs a simple database query.
                    Originally posted by fjm
                    In your example, if you wanted to use another public method that has NOTHING AT ALL to do with any of the other methods, what do you do? Do you make another class for it? Say for example that you wanted to have another function that said goodbye but instead of using the person's first name, you would be required to use their last name.
                    Even if the method does nothing but take a name and echo it back to you in a "You have been logged out, $lastname. Goodbye." sort of way, If it is related to the class (a User class, in this scenario), then it should belong to it.
                    Even tho it may seem pointless to add this to the class, it may become imporant later on.

                    Imagine if, after using this goodbye method in 200 pages, the requirements are changed. You are now required to print a language specific message depending on the language set in the constructor. It's a simple change if the method was in the class from the start. Not so simple if it was a rogue function.

                    Originally posted by fjm
                    OK. This goes back to what I was saying about the constructor. Instead of using a public method to do this, I thought the constructor was supposed to handle this which was why I designed it that way.
                    The constructor is only supposed to handle the initialization of the class; making sure all the members are set and ready to be used by the methods.
                    Likewise, destructors are meant to unset members and free resources.

                    This includes tasks like opening/closing database connections and running security algorithms. Anything not meant to be accessed by the outside, but needs to be run every time the object is created.

                    You can of course go beyond that if you want to, but be very careful. Bloated constructors are never good.
                    Providing a public method is usually better, and much cleaner.

                    It's also common to use constructor parameters as shortcuts to execute commonly used methods. (Like I do in the Animal example above.)

                    Originally posted by fjm
                    I have been doing a bit more reading on this and have looked over the link on interface. Not certain exactly how that would help me out just yet but of course it's because I don't fully inderstand it yet. I will re-read it and look for some additional info on that.
                    Using Interfaces isn't vital, nor really needed, in any one class.
                    Especially not since the class itself serves as a blueprint for how the class is meant to be used.

                    Interfaces are used to describe a group of classes, who are all meant to provide the same... well, interface to be used by other parts of the code.

                    Kind of like cars... They all share the same interface. A wheel, a gear shift, pedals, etc..
                    We can always be sure every car is built around this same basic interface, even tho they all implement it differently beneath the surface, and most of them add additional functionality on top.

                    This is exactly what interfaces do for classes. They ensure that classes provide at least the methods specified in the Interfaces they implement.
                    They help maintain the integrity of the classes from a design perspective, but add little to how the classes themselves are actually built or used.
                    (Any class built upon an interface could simply remove the implements keyword and function exactly the same afterwards.)
                    Last edited by Atli; May 21 '09, 04:16 AM. Reason: Spelling

                    Comment

                    • dlite922
                      Recognized Expert Top Contributor
                      • Dec 2007
                      • 1586

                      #11
                      Frank,

                      To summarize, Classes should sort of "group" certain behavior or functionality together. For formatting an output (ie your hello example) a function would do, but let's say you had a formatter class that contained several of these things and were used through out your application. To this point, one of the core values of OOP is code reuse.

                      Also use OOP to define "objects" instead of "functions" . For example your application might have a User class, and ATM class, and a Storage class instead of having function classed like "Deposits", or "Transactio n" classes. These functions will fall into behaviors of the objects themselves, ie

                      User::setBalanc e("5000");
                      User::changeAdd ress("123 Main");
                      ATM::getMenuOpt ions();
                      Storage::record Transaction();

                      To me, it looks like you're on the right track. As you continue to read and write code, you'll be able to see what the best way to implement classes keeping the values of OOP in mind: Encapsulation, Code Reuse, Divide and concur the problem, and Bug Containment.

                      Next topic I recommend for you is Exceptions/Error handling.

                      BTW: I'd like to point out this has been the best OOP thread on bytes and see how others could benefit from it.

                      See you around!




                      Dan

                      Comment

                      • Markus
                        Recognized Expert Expert
                        • Jun 2007
                        • 6092

                        #12
                        Originally posted by Atli
                        Depends on how you look at it, and might well be a matter of personal preference.

                        Would the function be using any class variables?
                        Would it even be related to the class itself?
                        [...]

                        Very well said. Great read :)

                        Comment

                        • fjm
                          Contributor
                          • May 2007
                          • 348

                          #13
                          There is some really great information here. Thanks for all the help guys. I am going to digest this and respond this weekend when I have a little more free time. I've already read this over once and will re-read it again this weekend before I respond. I'm not going to let this thread die!! :)

                          Comment

                          • Markus
                            Recognized Expert Expert
                            • Jun 2007
                            • 6092

                            #14
                            Originally posted by fjm
                            There is some really great information here. Thanks for all the help guys. I am going to digest this and respond this weekend when I have a little more free time. I've already read this over once and will re-read it again this weekend before I respond. I'm not going to let this thread die!! :)
                            Go to your local library and find some books on programming design patterns / OOP. It doesn't really matter what language they're in; the concepts are relatively the same.

                            Comment

                            • fjm
                              Contributor
                              • May 2007
                              • 348

                              #15
                              Thanks for the advice Markus. I'll do that. I seem to do better with books anyhow.

                              Comment

                              Working...