Nameless12 Posted February 15, 2007 Share Posted February 15, 2007 how does everyone implement the observer pattern?? I am just curious if there are some possible approaches I may not be aware of, I want to refactor a lot of code so I can start to replace some of the abstraction with observers. I dont want this to be limited to the observer pattern, if you have another way that you manage the problem, im all ears. A code critique of my own implementation could also be good, here is my current observer implementation. an example <?php class Logger { public static $n; public function index() { ++self::$n; echo "<h1 style=\"margin:0\">this is constructor: called " . self::$n . " times</h1>\n"; } public function start($one) { echo "state:start<br />\n"; echo "arg_1:$one<br />\n"; echo "processing data<br /><br />\n"; } public function finish($one) { echo "state:finish<br />\n"; echo "arg_1:$one<br />\n"; echo "cleaning up data<br /><br />\n"; } } class Login extends Observable { public function init() { echo "<br />exec:<br />\n"; $this->start(); $this->finish(); } public function start() { $this->setState('start', 'this is the start'); } public function finish() { $this->setState('finish', 'this is the end'); } } $o = new Login(); $o->connect(new Logger()); $o->connect(new Logger()); $o->init(); ?> here is the output of the above code exec: this is constructor: called 1 times state:start arg_1:this is the start processing data this is constructor: called 2 times state:start arg_1:this is the start processing data this is constructor: called 3 times state:finish arg_1:this is the end cleaning up data this is constructor: called 4 times state:finish arg_1:this is the end cleaning up data here is the code for the Observable class <?php abstract class Observable { private $_state = ''; private $_observers = array(); public abstract function init(); public function connect($o) { $this->_observers[] = $o; } public function setState($state) { $default = 'index'; $args = func_get_args(); array_shift($args); $this->_state = $state; foreach ($this->_observers as $o) { if (method_exists($o, $default)) call_user_func_array(array($o, $default), $state); if (method_exists($o, $state)) call_user_func_array(array($o, $state), $args); } } } ?> Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/ Share on other sites More sharing options...
Jenk Posted February 15, 2007 Share Posted February 15, 2007 Similar, but I opt for interfacing over method_exists() - if my application is trying to force an observer upon an non-observable object, I would like to know about it. I'm also not quite sure why you are using it as abstract.. the observerable (observer manager) should be a standalone object in it's own right. A chopped down verison: <?php interface Observer { public function notify($state); // what the object does with the state is up to the object. } final class ObserverManager { private $_observers = array(); private $_state; public function registerObserver (Observer $ob) { $this->_observers[] = $ob; } public function changeState ($state = null) { $this->_state = $state; $this->observe(); } public function observe(); { foreach ($this->_observers as $ob) { $ob->notify($this->_state); } } } ?> Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-185343 Share on other sites More sharing options...
Nameless12 Posted February 15, 2007 Author Share Posted February 15, 2007 I'm also not quite sure why you are using it as abstract.. the observerable (observer manager) should be a standalone object in it's own right. I always thought it was meant to be abstract?? but that said I will continue to use it as abstract because I plan on using this class in multiple objects an it is just good to do for a code reuse and consistency point of view. if my application is trying to force an observer upon an non-observable object, I would like to know about it. yeah but the way I'm using method exists rules that out. Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-185351 Share on other sites More sharing options...
Jenk Posted February 15, 2007 Share Posted February 15, 2007 I'm also not quite sure why you are using it as abstract.. the observerable (observer manager) should be a standalone object in it's own right. I always thought it was meant to be abstract?? but that said I will continue to use it as abstract because I plan on using this class in multiple objects an it is just good to do for a code reuse and consistency point of view. The aim of the observer is to loosely couple objects, not directly tie them. Extending breaks the first rule of this - it is class dependant, not object/interface dependant. It is also a code smell, because you will have multiple objects with two (or more..) behaviours. Objects should be concise. Let's say you extend foo with Observable. You want foo, but don't need the observer everytime - yet because of the extension, you are stuck with it. That's extra weight which you don't need. if my application is trying to force an observer upon an non-observable object, I would like to know about it. yeah but the way I'm using method exists rules that out. No, it doesn't. If you register an object for observing, but it doesn't have a $state or $default method, you'll never know. Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-185377 Share on other sites More sharing options...
Nameless12 Posted February 15, 2007 Author Share Posted February 15, 2007 about your first point, my book shelf says otherwise. And if there is an instance where I cant or dont want to extend it, it will be very easy to make an exception where needed. All the books and documentation I have seen show an extended version. The classes I intend to use it on will be designed in a way they need the extra weight. because my adding the extra weight it allows me to just move code to the observers instead of the main class, I could use abstraction but there are a few things I am thinking about that would be quite better with the observable class. About the second point you are wrong because I don't want the default index method to be forced, I want it to be optional an interface would make this required. if I load an object with a method called something if I set the state to the name of the method to the name of the state the method will be executed, this behavior is dynamic and cannot be interfaced. Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-185839 Share on other sites More sharing options...
Jenk Posted February 16, 2007 Share Posted February 16, 2007 about your first point, my book shelf says otherwise. And if there is an instance where I cant or dont want to extend it, it will be very easy to make an exception where needed. All the books and documentation I have seen show an extended version. The classes I intend to use it on will be designed in a way they need the extra weight. because my adding the extra weight it allows me to just move code to the observers instead of the main class, I could use abstraction but there are a few things I am thinking about that would be quite better with the observable class. About the second point you are wrong because I don't want the default index method to be forced, I want it to be optional an interface would make this required. if I load an object with a method called something if I set the state to the name of the method to the name of the state the method will be executed, this behavior is dynamic and cannot be interfaced. First bit: That's contradicting your other posts - you "could" abstract it? You are abstracting it. Infact you are forcing it to be abstract. Extensions are not optional. A class either extends another class, or it does not. There is no calculated decision. (This is of course refering to run-time, not you typing out the definitions.) I also fail to see why you have forced abstraction, because what else would this behaviour need? Everything is there! If you're books are suggesting to include multiple behaviours within a single object, I suggest you burn those books. That is bad OO practice, period. It's known as "Blob classes" or "God classes." Second part: That's the fundamentals of interface design. Objects that are observable should implement the same method for notification. Period. You will end up with a huge mess of "ok, which method is used for notification now?" Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-186156 Share on other sites More sharing options...
Jenk Posted February 16, 2007 Share Posted February 16, 2007 Also another contradiction you have is the abstract method init(). You say you don't want to force an "index" method on your object that extend Observable but at the same time, you are forcing them to implement an init() method.. You also seem to be confusing the Observer with the Observable. The Observable (which I prefer to call the Observer Manager) is the one that other objects tell it "Hey, I've changed something. This is my message: something!" which then goes and tells all the registered Observers "something." The observer is then responsible for reacting to the change. Here is an example of an observer; my previous example was the Observable (Observer Manager) <?php class Foo implements Observer { private $_message; public function __construct ($message) { $this->_message = $message; } public function notify ($state) { if ($state == 'BAR') { $this->printMessage(); } } public function printMessage () { echo $this->_message; } } ?> Here is a class that Foo is Observing: <?php class Bar { private $_foobar; public function __construct () { $this->_foobar = 'FOOBAR!'; } } ?> And here we have the context: <?php $observerManager = new ObserverManager(); $observerManager->registerObserver(new Foo('FooBar!')); $bar = new Bar(); $observerManager->changeState('BAR'); ?> The output will of course be: FooBar! From that context, do you now see why they observer manager does not need to be (and should not be) abstract? Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-186193 Share on other sites More sharing options...
utexas_pjm Posted February 16, 2007 Share Posted February 16, 2007 Also another contradiction you have is the abstract method init(). You say you don't want to force an "index" method on your object that extend Observable but at the same time, you are forcing them to implement an init() method.. I just wanted to clarify that implementing a method in an abstract class does not force a child class to implement the afore mentioned method. If the child class does not override the parent's method the child class will just inherit the abstract classes method. It is sometimes the case that you don't want children to override certain behaviors of the parent hence the use of the `final` keyword. Interfaces on the other hand will force any classes which implement them to actually provide their own implementations of the methods set forth by the interface. I think this was just misspoken by jenk "them to implement an init() method" => "them to inherit an init() method". Best, Patrick Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-186480 Share on other sites More sharing options...
Jenk Posted February 16, 2007 Share Posted February 16, 2007 Also another contradiction you have is the abstract method init(). You say you don't want to force an "index" method on your object that extend Observable but at the same time, you are forcing them to implement an init() method.. I just wanted to clarify that implementing a method in an abstract class does not force a child class to implement the afore mentioned method. If the child class does not override the parent's method the child class will just inherit the abstract classes method. It is sometimes the case that you don't want children to override certain behaviors of the parent hence the use of the `final` keyword. Interfaces on the other hand will force any classes which implement them to actually provide their own implementations of the methods set forth by the interface. I think this was just misspoken by jenk "them to implement an init() method" => "them to inherit an init() method". Best, Patrick It's an abstract method, it *has* to be implemented else you cannot extend the abstract class. Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-186551 Share on other sites More sharing options...
utexas_pjm Posted February 16, 2007 Share Posted February 16, 2007 Sorry, it's an abstract *method*. I misunderstood. Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-186581 Share on other sites More sharing options...
Nameless12 Posted February 17, 2007 Author Share Posted February 17, 2007 about your first point, my book shelf says otherwise. And if there is an instance where I cant or dont want to extend it, it will be very easy to make an exception where needed. All the books and documentation I have seen show an extended version. The classes I intend to use it on will be designed in a way they need the extra weight. because my adding the extra weight it allows me to just move code to the observers instead of the main class, I could use abstraction but there are a few things I am thinking about that would be quite better with the observable class. About the second point you are wrong because I don't want the default index method to be forced, I want it to be optional an interface would make this required. if I load an object with a method called something if I set the state to the name of the method to the name of the state the method will be executed, this behavior is dynamic and cannot be interfaced. First bit: That's contradicting your other posts - you "could" abstract it? You are abstracting it. Infact you are forcing it to be abstract. Extensions are not optional. A class either extends another class, or it does not. There is no calculated decision. (This is of course refering to run-time, not you typing out the definitions.) I also fail to see why you have forced abstraction, because what else would this behaviour need? Everything is there! If you're books are suggesting to include multiple behaviours within a single object, I suggest you burn those books. That is bad OO practice, period. It's known as "Blob classes" or "God classes." Second part: That's the fundamentals of interface design. Objects that are observable should implement the same method for notification. Period. You will end up with a huge mess of "ok, which method is used for notification now?" 1. removal of abstract keyword is something i did 2. the books showed extended classes, extended classes are not god classes so wtf are you going on about 3. it wont be a big mess, documentation is a factor yes but that does not make it a mess.. it is very easy to remember that index() is default, if i have an index i can easily figure out what the states are. The idea of having it access methods based on the names will actually make my life a lot easier... 4. the Init() was there because you cannot add observers before you create an object and because i was extending the class at the time i realized I had to have a second constructor I have never had reason to implement the observer pattern in a real application before and i do realize adding it to $this->_state is a better solution at the time i was using gtk as inspiration #create a new window $w = new GtkWindow(); #connect it to a function $w->connect('destroy' array('gtk', 'main_quit'); #equivalent of init $w->show_all(); #loop gtk::main(); Interfaces are not required the way I plan on doing it I will remove the abstract keyword from this class, that is all, interfaces are not needed in this situation and if it was not for the fact php does not allow for extending multiple classes directly then the other implementation would be more valid. But like I said I over looked something I already knew for a stupid reason and partly because I have never had use to implement the observer pattern in a real app before the only real time i have used it a lot is in GTK and i did not write gtk! There are pros and cons to doing it both ways and I will want to be open to both ways and that is why I will remove the abstraction but If you want to connect objects from outside the object it is easier to do it my way and if you doubt me just ask your self why gtk does the same thing Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-187194 Share on other sites More sharing options...
Jenk Posted February 18, 2007 Share Posted February 18, 2007 Well, you're screwed if your object class needs to extend another class, yet you need to include observer functionality. You're breaking the entire purpose of an observer by tightly coupling the object/class, and you don't seem to understand interfaces at all (i.e. if it's a particular object, it should have the same interface as all other objects with the same behaviour.) And to address your points: 1. ok. 2. Yes they are. They will be blob/god objects because they cater for more behavioural functionality than is needed. 3. You're sounding like businessman, the same person you instructed to take advice from others.. Having non-uniform states and interfaces for multiple objects will be a big mess. Documentation is supposed to accompany and hint, not completely dictate and explain. 4. __construct() .. Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-187618 Share on other sites More sharing options...
Nameless12 Posted February 18, 2007 Author Share Posted February 18, 2007 1. I know interfaces 2. I am not line business man 3. I did make changes and get ideas from what was said 4. yes i rejected the idea of an interface in this case because with the if method exists code it would be stupid. It would only be applicable if i removed those lines, then an interface would be applicable. But you did not say that you said to just add an interface and that is just plain wrong why i am using if method exists 5. __construct() you dont seem to understand making the new object runs the constructor, then you add the observers and then you once again would have to run the constructor by the time you are done running the constructor a second time you have executed the constructor twice. 6. extending classes, well the observer pattern was around long before php and guess what? other programming languages can extend from multiple classes directly the fact php cannot is a limitation of the php language its self. you might think its wrong to implement it that way , I never said it was right. But when it comes to allowing functionality such as the functionality i was using as a bit of a guide for what I wanted to do It adds objects from outside of its object with connect, it connects them to various parts of the programs execution and if not done by extending you will have to recreate the init() and connect() setState() and getState() methods regardless of if you are using the approach you love so much because there is no other way to add objects from the outside. I think you ignored what I said about phpGTK because of what you said about __construct() #create a new window $w = new GtkWindow(); #connect it to a function $w->connect('destroy' array('gtk', 'main_quit'); #equivalent of init $w->show_all(); show_all() is used to build the object, so is show(); and if these methods are not called directly they are called by the object they are placed inside. to draw everything, prior to this the object just takes in properties\settings such as what objects are going to connect to it. It is exactly the same reason as why i was trying to do it the other way and why this approach gtk uses may be different to your observer that does not make an inferior implementation. Just because someone does not use your advice does not mean I have not heard it and understood it, I took advice and suggestions and acted upon it and got ideas. You try to say I am like Businessman he is not like that, he nods his head and says thank you very much and then does not do a damn thing.. It is completely different. If you respond to argue the issue i am not interested but if you do have advice to do a similar implementation to the way gtk does it i would like to hear it, but based on what you told me already i know how you would probably do it and have been thinking that i will do it the same way. That is by having the object stored in the class properties and being forced to recreate the methods and make them call the stored object. And I would only be doing this to work around the fact php does not allow for multiple inheritance, oh and we cannot forget you would use an interface. Well I would too depending on the situation if i use if method exists I will not be, otherwise I would. They are a different approach, your idea that no interface is wrong is bias. Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-187710 Share on other sites More sharing options...
Jenk Posted February 18, 2007 Share Posted February 18, 2007 with the if method exists code it would be stupidI wonder what the answer to that is, then? 5. __construct() you dont seem to understand making the new object runs the constructor, then you add the observers and then you once again would have to run the constructor.That is a flaw in your design. Observers never - ever - re-run constructors. I can't think of any objects that ever do re-run constructors. The only instances where a constructor is called explicity is when an extended class calls it's parent/superior classes constructor.They are a different approach, your idea that no interface is wrong is bias.Bias? No. A Practice learnt through experience? Yes. Documented (via books/lecture papers) good practice by people such as Martin Fowler, "Gang of Four", etc.? Yes. The references I make to "interface" is not that of "you must use the keyword 'implements'" it is referencing that you should use a common name for your observer method(s) throughout all objects that share that functionality. Let's take a different look at it. Java's "toString()" method, existing on all objects. As a developer, I can be assured that which ever object I need to get the string value from, it will always be the toString method I need to call. Your example, I will need to look up some documentation (which may not exist anymore) or open the class and have a look. I can't just call the toString() function, because I cannot be assured it will exist. The same applies to the method for observers. If I want to notify my observers of a new state, I can be assured that they will all have the "notify()" method. In your example, I would need to first check they do/don't have "index()" and then if they don't, I'll see if they have the method with the same name as the state change method. If they don't have that, they'll never know of the state change. You are also still ignoring the issue of including multiple behaviours into one object - which is bad practice, period - and also that you have abstracted the observable - not the observer. RE: GTK I couldn't give a monkeys if you are using this for the online bible; it is bad practice to include multiple behaviours into objects. Extensions are used to remove duplication of code; by storing said code into one class that can be utilised by many others that will require this code, but the code on it's own will not be a complete object. What you originally posted was complete code, it will function fully as an observable (observer manager) object. It does not need an "init" function within the same object, it does not need any other functionality, so it does not need to be extended to make use of it. "class Foo extends Observable { public function init() {} }" would be a valid, fully functional object with what you have posted - this is why it is unecessary to make it abstract, and also unecessary to specifiy it must have an init() method, when init() is never called by any of your abstract class methods, and so none of them are dependant on it. Quote Link to comment https://forums.phpfreaks.com/topic/38620-observer-pattern-implemenations/#findComment-187723 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.