How do two objects communicate (w/ example inside) - oop

If two children have the same parent, how does an event firing from one child get handled by the second child.
So the example is:
TrackerContainer is the parent of Tracker and TrackerPanel. TrackerPanel is the parent of PlayButton. Tracker is a timer-like class and has a stop() method. PlayButton has an activate() and deactivate() method.
How does a call to the stop() method from within Tracker call the deactivate() method from within PlayButton(). I thought of having the time keeping track of occurring in the TrackerContainer class, but that doesn't feel right.
EDIT Here it is in code (JavaScript, by the way):
function TrackerContainer
{
this.display = new Tracker();
this.panel = new TrackerPanel();
}
function Tracker
{
this.play = function() { /* yada */ }
this.stop = function() { /* yada */ }
}
function TrackerPanel
{
this.playButton = new PlayButton();
}
function PlayButton
{
this.activate = function() { /* method called when Tracker is playing */ }
this.deactivate = function() { /* method called when Tracker is stopped */ }
}

You didn't indicate the language, so we'll talk in general terms. This is the Model-View-Controller pattern. Your PlayButton is a view. Your Tracker is the model and the TrackerContainer is the controller (I'm guessing; it might be a view, in which case you should have a separate controller object).
The view's job is to display things. The model's job is keep track of data. The controller coordinates between the two.
For this problem, you probably want an Observer pattern. The controller observes the model and updates the view as needed. One way to implement the Observer pattern is with a delegate or listener. You create an interface called TrackerListener that TrackerContainer conforms to, with methods like trackerDidStart() and trackerDidStop(). Tracker HAS-A TrackerListener and calls the listener methods whenever the state changes. TrackerContainer then updates the button's state.

The simplest solution would be to pass the Tracker a instance of the PlayButton. The tracker, in stop() would call playbutton.deactivate(). If it makes you feel more oop-complient, you could make PlayButton implement a Deactivatible interface, which the tracker would work with.

Related

Confusion about single responsibility in OOP

Let's consider the following example:
class User
{
}
class FirstUseNotification
{
function show(User user)
{
// check if it was already shown, return if so
// show a notification
// mark it as shown in the db or whatever
}
}
class SomeController
{
function someMethod()
{
firstUseNotification->show(user);
}
}
The show() method seems to break single responsibility by doing 3 things. So i figure this could be rewritten as such:
class User
{
}
class FirstUseNotification
{
function show(User user)
{
// show a notification
}
function shouldShow(User user)
{
// return true if not yet shown
}
function markAsShown(User user)
{
// flag notification as shown
}
}
class SomeController
{
function someMethod()
{
if (firstUseNotification->shouldShow(user))
{
firstUseNotification->show(user);
firstUseNotification->markAsShown(user);
}
}
}
So here's what i'm interested in:
Am i correct to assume that in second example the notification class is now OK with single responsibility principle?
All of the things that were happening in show() method are gone, but ... they are simply relocated to a method in a controller, so shouldn't it mean that this controller method now breaks single responsibility? If so, how can this be done to comply?
The single responsibility principle (SRP) is often stated in the form of a quote by Robert C. Martin:
A class should have only one reason to change.
In this case, the purpose of your FirstUseNotification class is to show a notification to a first-time user. So the only reason this class should need to change is if this purpose changes; and that is one reason, so the SRP is satisfied.
Note that this definition applies to a class, not to a method. That said, splitting this method into three methods probably violates the SRP, because if a user of this class needs to call three methods instead of one, then that user class has the responsibility of checking whether to show the notification, and marking the user as shown, in addition to the user class's own responsibility. FirstUseNotification's responsibility is to "show a notification to a first-time user", not to provide an API that allows other classes to do that when it is not their responsibility.
In practice the FirstUserNotification class might have other reasons to change, if the details of how it shows the notification or accesses the database change. This can ideally be prevented by having stable interfaces for the notification and database classes, so that changes to those classes don't require changes to FirstUseNotification or other classes which show notifications and/or access the database. In practice this is not always 100% achieved, in which case the FirstUseNotification class might have some responsibilities to do with the details of showing a notification or accessing the database. But in theory, if those other classes handle their own responsibilities properly, then this class has only one reason to change.

OO Design Issue related to subclassing

I have a parent bean having one instance variable like below :
public Class ParentBean {
protected boolean show; // this variable will be used to show some UI component
public void action() {
// update show variable here
}
public boolean isShow() {
return show;
}
}
Is it a good design if I want to reuse the "show" variable in a child bean (to show other UI component specific to child bean ) as shown below :
public Class ChildBean extends ParentBean {
// override the action method from parent bean
public void action() {
// update show variable here
show = true /false;
}
}
In effect , show variable is being updated by "childBean" by overriding action() method.
Is this a good design practice ? Otherwise same thing has to be repeated in ChildBean to get this work done.
If you use the show variable for the same purpose in the subclass, as you seem to be doing in this example, then obviously you should reuse it, because otherwise you just end up writing the same code twice, which is contrary to the point of OOP.
In general, in OOP, it is common to override superclass methods in subclasses, as well as modifying superclass instance variables, as long as you know what the variable you are modifying is being used for (you don't want to be randomly changing instance variables in classes that you don't completely understand, or don't have access to the source of, because you don't want any unfortunate side effects), so when it's your own code, this is absolutely fine.
As a general guideline, if your options are either to copy and paste a massive hunk of code and use it unchanged, or subclass and use the superclass' instance variables or functions, it's better to subclass. Otherwise, you're missing out on the point of OOP.
Changing the value in subclass will not affect superclass variable
This is fine with respect to the design. When a subclass object is instantiated, it will have a different copy of variable. and If superclass object is instantiated it will have different copy.
It is. Having a protected variable means you are allowed to modify it into parent or children classes (remember every single instance of each class has its own property values). So, if you have some generic functionality which is valuable for all the children:
Parent class:
public void action(){
//update show variable here
show = true;
}
Appart from that, if you want to add some extra functionality in a specifical child:
Child class:
#Override
public void action(){
super.action();
//Extra functionality goes here
//You can also access parent's 'protected' fields
if (show){
System.out.println("Shown");
}
}
An example of the use:
Parent p = new Parent();
p.action();//Prints nothing
Child c = new Child();
p.action();//Prints 'shown'

Connecting data to a GUI - OOP

I have an application with several graphs and tables on it.
I worked fast and just made classes like Graph and Table that each contained a request object (pseudo-code):
class Graph {
private request;
public function setDateRange(dateRange) {
request.setDateRange(dateRange);
}
public function refresh() {
request.getData(function() {
//refresh the display
});
}
}
Upon a GUI event (say, someone changes the date range dropdown), I'd just call the setters on the Graph instance and then refresh it. Well, when I added other GUI elements like tables and whatnot, they all basically had similar methods (setDateRange and other things common to the request).
What are some more elegant OOP ways of doing this?
The application is very simple and I don't want to over-architect it, but I also don't want to have a bunch of classes with basically the same methods that are just routing to a request object. I also don't want to set up each GUI class as inheriting from the request class, but I'm open to any ideas really.
As you commented the methods are identical. In that case I would suggest the following approach.
abstract class AbstractGUIElement {
protected request;
public function setDateRange(dateRange) {
request.setDateRange(dateRange);
}
abstract function refresh();
}
Refreshing would probably be element specific so I have added it as an abstract method the inheriting types have to implement.
class Graph extends AbstractGUIElement {
public function refresh() {
// Graph specific refreshing
}
}

Yii: attaching events to models

I have a User model which is bundled in a module installed on my Yii application. This module is third party and I do not want to alter its code.
I also have a Cv Model that has a BELONGS_TO relation with the User model.
My question is: How can I delete the cv when a user is deleted ?
I know that I can achieve this with on delete cascade ... on mysql. However, i do need to delete other data such as a photo, files, etc.
What I have tried
I have created a component that is preloaded on my application. This component attaches to an onAfterDelete event
class EventListener extends CComponent
{
public function init() {
Yii::import("application.modules.users.models.User");
User::model()->attachEventHandler('onAfterDelete', array($this, 'deleteUser'));
}
public function deleteUser($event)
{
// stuff here ...
}
}
However this does not work.
Any suggestions ?
This may help you.
User::model() is a singleton
$user1 = User::model();
$user2 = new User; // will be used in insert action
$user3 = User::model()->findByPk(10); // will be used in update/delete action
$user1, $user2 and $user3 are completely different objects.
You can attach events to objects, in this case you have to add events to all these 3 objects individually.
$user1->attachEventHandler(...);
$user2->attachEventHandler(...);
$user3->attachEventHandler(...);
look like Yii does not provide any way to add events at Class level.
Well, guys, I have just stumbled upon the same problem and I solved it this way:
You should use the init() of a Model, not your event listener collection class.
In my case I have devModel class:
public function init()
{
parent::init();
$this->onLicenseUpdated = array(new MEventProcessor, 'licenseUpdateHandler');
}
And the handler is licenseUpdateHandler($event) in a MEventProcessor class.
This way every time you work with model instance, it'll call init() for every object and attach the event handler to every instance of this Model.
Now any time the event (in my case onLicenseUpdated()) is invoked for the model - the handler will be called too.
You could also to use Behaviors.
1 - behaviors can listen to events : you just have to override their events() method
class MyBehavior extends Behavior {
public function events() {
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event) {
// ...
}
}
2 - although it is more common to attach a behavior to a component in the component's behaviors() method, you can also attach them dynamically and keep the original code unmodified :
use app\components\MyBehavior;
// attach a behavior object
$component->attachBehavior('myBehavior1', new MyBehavior);
You will find some useful documentation here :
yii 1 : http://www.yiiframework.com/doc/api/1.1/CBehavior
yii 2 : http://www.yiiframework.com/doc-2.0/guide-concept-behaviors.html

robotlegs: I have 2 views and mediators that have in common 1 thing how can I DRY it?

I have 2 views that show lists that then uses a mediator to get data. but I want in some way to DRY it so I don't have to repeat my self 2 times for the same thing. how do I do it?
EDIT1(code):
[SkinPart(required="false")]
public var WOListsDDL:DropDownList;
// in partadded
case WOListsDDL:
// when the selected list is changed in the lists drop down list
WOListsDDL.addEventListener(IndexChangeEvent.CHANGE, _WOListsDDL_changeHandler);
WOListsDDL.dataProvider = new ArrayCollection();
WOListsDDL.labelField = 'title';
break;
//
protected function _WOListsDDL_changeHandler(event:*):void{
_debug('List selection changed handler.');
_getContentsForList();
}
protected function _getContentsForList():void{
_debug('Getting list items.');
getItemsSignal.dispatch({key: getSelectedList()._key, itemType: 'item'});
}
public var getItemsSignal:GetItemsSignal = new GetItemsSignal();
override public function mediatorComplete():void{
getItemsSignal.dispatch({key: tottysAuth.getCurrentUser()._key, itemType: 'list'});
}
// then in my mediator
[Inject] public var getItemsSignal:GetItemsSignal;
override public function onRegister():void{
// view listeners
view.getItemsSignal.add(_getItemsSignalHandler);
}
protected function _getItemsSignalHandler(input:Object):void{
getItemsSignal.dispatch(input);
}
this all for one view-mediator. now I have 2 view-mediators that are doing these tasks. How to make them dry?
Solutions I have:
make a little view containing the dropdown list with a mediator that is listening for the event. in the big components they are listening for a signal in the view of this little component. nothing more. it seems quite well but i don't think is so great
So there is functionality on both the views and the mediators that you'd like not to repeat?
You could put the code you want to reuse in another object and call its methods from your multiple views and mediators. Or you could put it in ancestor classes and extend each of those classes in both your view and your mediator.
Best practice would be to do the former and not the latter.