I am in the process of building a Cocoa app, which is comprised of a window divided in 3 sections. Each section is responsible for its own business and there are around 30 controls in it between table views, pop up buttons etc.
I started with a single Controller but things get messy pretty easily, so I decided to break the logic down in 3 controllers object (one each section of the view). I then created the NSObject reference on Interface Builder and hooked up all the outlets, actions, data sources and delegates. So far so good.
Now, the three sections pass objects to each other and therefore I need a way to set an object from one class to another. The object in question is a class variable, but as I have no reference to the object I don't know how to pass it around.
Is there a way to do this or is this just the wrong approach overall?
Solution:
As Sergio mentioned below in one of the comments, the solution seems to be to create a weak reference to the other controllers inside each controller as IBOutlet and then in the Xcode Interface Builder link the controller objects together. As a result, now each controller can access the exposed methods and variables of the referenced controllers.
Now, the three sections pass objects to each other and therefor I need a way to set an object from one class to another. The object in question is a class variable, but as I have no reference to the object I don't know how to pass it around.
What seems missing in your design is a Model (as in Model-View-Controller). This would be a class encapsulating all the state of your app, even if it is transitory state, so that each affected object have access to it.
One easy implementation for such a model class is a singleton, so that it is readily available in all of your controllers. Have a look here for some thought about the implementation of a singleton in Objective-C.
Once you have your model class, your controllers could access it like this, e.g.:
[MyModel sharedModel].myObject = ...;
This approach is good, IMO, if it makes sense for you to go in the direction of creating a Model for your design. This depends on the semantics of the object that your controllers share. So, there might be alternative solutions better fit for your case. E.g., one controller could be the owner of the shared object, and the other two could receive a reference to the first controller on init so that they can access its public properties.
Related
I've looked through the other questions and am still struggling so if anybody could take the time to look at this, it would be much appreciated :).
I currently have my app working fine but I've been reading and have decided it doesn't fit the MVC design pattern. I am still learning lots about design and would like to edit it so that it is more sound.
I think I know what should go in to my model class, and I think that it should be instantiated in the app delegate. My questions are: why in that location? Is lazy instantiation the best/correct way to do this? And finally, once initiated, do I use a property to access the class or do you use special methods?
Sorry for the overload; I am also trying to get my reputation up enough to vote on other questions! :)
It's really hard to answer a general question like this, since there are so many ways one could implement any particular project. In general, I don't think that instantiating a model class in your app delegate is necessarily the way to go. Since a controller class mediates between the model and the view, it's often better to instantiate your model in a controller class -- for instance, I have a program that keeps track of the plants in my garden, and my controller class is a subclass of NSArrayController. It seems to make sense to create new plant objects in the controller and then just add them to its arrangedObjects. I try to have as few connections (via properties or ivars) between classes as I can, the thought being that each class should take care of its own business as much as possible. Often, you don't need to have a reference to the class, because you are calling class methods to create new objects, and then those objects can access any instance methods of that class without any explicit reference to the class.
I find myself needing to have a View expose its Model and Controller references. Is this the smell of bad design? Or is this considered "safe" practice?
For example: I have a list (composed of a ListView, ListController, and ListModel) and many list items (composed of a ItemView, ItemController, and ItemModel).
When I create the ItemModel, ItemView, and ItemController for each list item, I pass the ItemView instance off to the ListView. But, at some later point, my ListController needs a reference to the corresponding ItemController instance.
So, would it be more proper to pass both the ItemView and the ItemController in to ListView::addItem(), or just pass in ItemView and expose an instance method such as ItemView::getController()?
Or doesn't it matter? Is each approach equally viable? If followed to their logical conclusion, does either tactic result in an anti-pattern?
But, at some later point, my ListController needs a reference to the corresponding ItemController instance
Why? If you're decoupling your classes properly, you shouldn't need this.
Controllers almost always address a functional domain. An example of such a domain might be "Sales" or "Admin." In addition, MVC also supports the use of "Areas," which provides an additional hierarchical level of organization.
Adding references to controllers from other controllers is at cross-purposes with this organizational structure. If you need to combine functionality to make your code more DRY, ordinary refactoring will accomplish that. You can also inherit controllers from a base class containing common functionality.
In the mvc pattern the users request shall be routed to a controller, say invoicecontroller, that has actions.
Lets say the default action, Index, returns a list of invoices; the controller then creates a model with a list of invoice objects, instantiates the correct view and injects the model into the view.
Now it is the views turn to do its magic. It renders the best view it can with the data it has, which may include routes to one or more controllers.
In NO instance should the view (or model) do business logic themselves.
That said, I totally agree with Jakub. Hope that helps.
Considering you are not actually showing any code at all.
In my opinion, you should change your design. A controller is not supposed to communicate with another controller (directly), MVC dictates it: reference.
If you need to invoke a controller action from another controller, consider using delegates or composition. Instead of directly invoking the controller action.
Could anyone give an example of why it would be advantageous to use MVC instead of a simpler Model and a View only.
Note: whether it's called MVC or MVP (Model-View-Presenter), I'm talking about the one where the View receives input, then the Controller will respond to the input event by interpreting the input into some action to be done by the Model. When the model changes, the View will update itself by responding to events from the model.
What is disadvantageous of simply letting the Model respond to events in the View and vice versa?
In MVC, if I changed the model in a way that affects the controller then I'll have to do changes in the controller. In Model-View, if I change the Model, I'll have to update the view.
So, it seems like we are introducing complexity by adding the "controller" part?
In MVC, the Model is blind to its environment, the view can be too - passing off (blindly) its events to the controller, which knows more about the view and model. So when all is said and done, the controller is the 'non-reusable' disposable part of the system, since it is the most context aware component.
if I changed the model in a way that affects the controller...
The the model should expose simple CRUD methods in such a way that those using the methods do not have to know anything about the passed update object, nor what really happens inside the model.
This means that the view, IMO, has to do a bit of work by creating the passed record, since Controllers are supposed to be stateless and the view is more persistent. Controllers get triggered and 'kick-in' do their work with a passed object and do not have a state.
The passed data is created by some sort of generic convention.
Let me go even further. Suppose you have a view, a tablegrid, and a control whose enabled property is dependent on item is selected in the grid -- you COULD create a view that handles both those controls and this logic internally, and that would probably be the way to go in such a simplified example.
But the more atomic your views are, the more reusable they become, so you create a view for every, yes every, control. Now you are looking at a situation where views have to know about each other in order to register themselves for the right notification...
This is where the controller steps in, since we want to stick all these dependencies onto him, the long term disposable one. So the controller manages this type of view-to-view notification scheme.
Now your views are ignorant as they can be and independent, thus reusable.
You can code a view without having to know about the system, or the 'business logic' as they like to call it. You can code a model without having to know too much about your goals (though it does help to tweak the model to enable it to return the datasets you have in mind).... but controllers, they are last and you have to have the previous two firmed up before you can wire things together.
Here is another thing to think about -- just as the Model is supposed to abstract-away and provide a generic interface to the underlying implementation of the data it is managing (the client does not know if the data comes from a DB, a file, a program setting, etc) -- the view should also abstract away the control it is using.
So, ultimately this means a view should not (caveat below) have functions/properties that look like this:
public property BackgroundColor{get;set}
Nor
public function ScrollBy(x,y){}
But instead:
public SetProp(string name, object val){}
And
public DoCmd(string name, object val){}
This is a bit contrived, and remember I said ultimately... and you ask why is this a good idea?
With reusability in mind, consider that you may one day want to port things from WinForms to, say, Flex, or simple want to use a new-fangled control library that may not expose the same abilities.
I say 'port' here, but that is really not the goal, we are not concerned with porting THIS particular app, but having the underlying MVC elements generic enough to be carried across to a new flavor -- internally, leaving a consistent and ability-independent external interface intact.
If you didn't do this, then when your new flavor comes along, all your hard references to view properties in the (potentially reusable/refactorable/extendable) controllers have to be mucked with.
This is not to mean that such generic setters and cmds have to be the interface for all your views abilities, but rather they should handle 'edge case' properties as well as the normal props/cmds you can expose in the traditional hard-link way. Think of it as an 'extended properties' handler.
That way, (contrived again), suppose you are building on a framework where your buttons no longer have buttonIcon property. Thats cool because you had the foresight to create a button view interface where buttonIcon is an extended property, and inside the view your conditional code does a no-op now when it receives the set/get.
In summary, I am trying to say that the coding goals of MVC should be to give the Model and View generic interfaces to their underlying components, so when you are coding a Controller you don't have to think to hard about who you are controlling. And while the Controllers are being (seemingly unfairly) set up to be the sacrificial lamb in the long run of re-usability -- this does not mean ALL your controllers are destined for death.
They are hopefully small, since a lot of their 'thinking' has been shoved off into semi-intelligent Models and Views and other controllers (ex: Controller to Sort a Grid or Manipulate a TreeView) -- so being small they can be easily looked at and qualified for reuse in your next project -- or cloned and tweaked to become suitable.
It actually reduces complexity by separating the workflow logic from the domain logic. It also makes it easier to write unit tests and makes your application easier to maintain and extend.
Imagine if you wanted to add a new data type. With the approach above, you would probably duplicate a lot of the workflow logic in the new class as it would be likely to be tightly coupled to the domain logic.
The discipline involved in separating the workflow logic into the controller makes it more likely that you will have fewer dependencies between workflow and domain logic. Adding a new data type would then be more simple, you create the new domain object and see how much of the controller you can reuse, e.g. by inherited from a controller super class.
It would also make it easier to change frameworks in future - the model would probably not change too much and so would be more portable.
Having said that, you might want to look into MVVM depending on what you are using as your presentation layer: Benefits of MVVM over MVC
Advantages of MVC/P (I am talking about Supervising Controller here) over MV include:
You can handle complex data binding code in the controller, if required.
You can test that complex presentation logic without a UI testing framework.
You can also have a graphic designer make your views, and not see your code, and not mess up your code when they fix your views.
I am developing an application that involves a type hierarchy and started by defining the models for each type via inheritance. When it comes to writing the corresponding controllers I am not sure how to approach the whole thing in a clean way. Should I write only one controller for the base type that is able to handle derived models or should there be one controller for each subtype? How should the view-controller bindings be set up to work with the different controllers?
You might want to check out SproutCore's new experimental polymorphism support: http://groups.google.com/group/sproutcore-dev/browse_thread/thread/b63483ab66333d15
Here's some information on defining sub-classes and overriding properties and methods:
http://wiki.sproutcore.com/w/page/12412971/Runtime-Objects.
From my (limited) use of Sproutcore, I've only been able to bind 1 view to 1 controller.
As such, if you are planning to use a single view (e.g. ListView) to display your data, then I think you will only be able to bind that view to 1 controller. This means the 1 base type that is able to handle derived models seems to be the way to go.
Typically you populate the content of ArrayController instances with the results of App.store.find calls. SC.Store#find can take an SC.Query instance, which typically looks like:
MyApp.myController.set('content') = MyApp.store.find(SC.Query.local(MyApp.MyModel));
This should return all instances of MyApp.MyModel, including any instances of MyApp.MyModel's subclasses.
The first argument to SC.Query.local can either be an SC.Record subclass or a string referring to the subclass. So if you've got some intermediary SC.Record subclasses, you might want to try using them there.
Controllers should just be proxies for objects, when dealing with single instances of your model. In other words, ObjectController can proxy anything. Here is what I mean in code:
You have two objects, Person and Student.
App.Person = SC.Object.extend({
// person stuff here
})
App.Student = App.Person.extend({
// student stuff here, you have have all Person things because you are extending person.
})
You then want to define controllers:
App.personController = SC.ObjectController.create({
contentBinding: 'App.path.to.person'
})
App.studentController = SC.ObjectController.create({
contentBinding: 'App.path.to.student'
})
note that you would only bind the controller's content to something if the person/student is a result of a selection, or some other flow where bindings fire. In other words, if you set the person manually (say from a statechart, as the result of an interaction), you would still define the controller but would do
App.personController.set('content', person);
You set up the controller differently depending on whether the Person is a 'top level' object in your app, or some intermediate object that gets selected. Also, you might only need one controller, you would only have a studentController and a personController if you were acting on a person and a student at the same time. Both are just ObjectControllers, and those can proxy anything.
Finally, in your view you would bind the relevant view element to the controller:
...
nameView: SC.LabelView.design({
layout: {/* props */},
valueBinding: SC.Binding.oneWay('App.personController.name')
})
...
note that the oneway binding is if the name is not going to be changed on the view, if the view can change the name, then just do a normal binding. Also note the path here. I am not binding to
'App.personController.content.name'
Since the personController proxies the object, you bind to the
'namespace.controller.property-on-object-controller-proxies'
If you are putting a lot of business logic in your controller, you are doing it wrong. Controllers should just be for proxying objects (at least ObjectControllers should be). Business logic should be on the models themselves, and decision making logic should be in statecharts.
I have two classes that each need an instance of each other to function. Ordinarily if an object needs another object to run, I like to pass it in the constructor. But I can't do that in this case, because one object has to be instantiated before the other, and so therefore the second object does not exist to be passed to the first object's constructor.
I can resolve this by passing the first object to the second object's constructor, then calling a setter on the first object to pass the second object to it, but that seems a little clunky, and I'm wondering if there's a better way:
backend = new Backend();
panel = new Panel(backend);
backend.setPanel();
I've never put any study into MVC; I suppose I'm dealing with a model here (the Backend), and a view or a controller (the Panel). Any insights here I can gain from MVC?
It's time to take a look at MVC. :-) When you have a model-view-controller situation, the consensus is that the model shouldn't be aware of the view-controller (MVC often plays out as M-VC), but the view is invariably aware of the model.
If the model needs to tell the view something, it does so by notifying its listeners, of which it may have multiples. Your view should be one of them.
In a circular construction scenario I'd use a factory class/factory method. I would normally make the construction logic private to the factory (using friend construct, package level protection or similar), to en sure that no-one could construct instances without using the factory.
The use of setter/constructor is really a part of the contract between the two classes and the factory, so I'd just use whichever's convenient.
As has been pointed out, you really should try to find a non-circular solution.
First of all, contrary to what others has said here, there's no inherent problem with circular references. For example, an Order object would be expected to have a reference to the Customer object of the person who placed the Order. Similarly, it would be natural for the Customer object to have a list of Orders he has placed.
In a refernce-based language (like Java or C#) there's no problem, at all. In a value-based language (like C++), you have to take care in designing them.
That said, you design of:
backend = new Backend();
panel = new Panel(backend);
backend.setPanel(panel);
It pretty much the only way to do it.
It's better to avoid circular references. I would personally try to rethink my objects.
panel = new Panel(backend);
You do this in this routine something like
Public Sub Panel(ByVal BackEnd as BackEnd)
Me.MyBackEnd = BackEnd
BackEnd.MyPanel = Me
End Sub
You don't need BackEnd.SetPanel
It is better to use Proxies. A proxy links one object to another through raising a Event. The parent hands the child a proxy. When the child needs the parent it calls a GetRef method on the proxy. The proxy then raises a event which the parent uses to return itself to the proxy which then hands it to the child.
The use of the Event/Delegate mechanism avoids any circular reference problems.
So you have (assuming that the backend is the 'parent' here)
Public Sub Panel(ByVal BackEnd as BackEnd)
Me.MyBackEnd = BackEnd.Proxy
BackEnd.MyPanel = Me
End Sub
Public Property MyBackEnd() as BackEnd
Set (ByVal Value as BackEnd)
priBackEndProxy = BackEnd.Proxy
End Set
Get
Return priBackEndProxy.GetRef
End Get
End Property
Here is a fuller discussion on the problem of circular references. Although it is focused on fixing it in Visual Basic 6.0.
Dynamic Memory Allocation
Also another solution is aggregating Panel and BackEnd into another object. This is common if both elements are UI Controls and need to behave in a coordinated manner.
Finally as far as MVC goes I recommend using a a Model View Presenter approach instead.
Basically you have your Form Implement a IPanelForm interface. It registers itself with a class called Panel which does all the UI logic. BackEnd should have events that Panel can hook into for when the model changes. Panel handles the event and updates the form through the IPanelForm interface.
User clicks a button
The form passes to Panel that the user clicked a button
Panel handles the button and retrieves the data from the backend
Panel formats the data.
Panel uses IPanelForm Interface to show the data on the Form.
I've been delaying implementing the lessons learned here, giving me plenty of time to think about the exact right way to do it. As other people said, having a clear separation where the backend objects have listeners for when their properties change is definitely the way to go. Not only will it resolve the specific issue I was asking about in this question, it is going to make a lot of other bad design smells in this code look better. There are actually a lot of different Backend classes (going by the generic class names I used in my example), each with their own corresponding Panel class. And there's even a couple of places where some things can be moved around to separate other pairs of classes into Backend/Panel pairs following the same pattern and reducing a lot of passing junk around as parameters.
The rest of this answer is going to get language specific, as I am using Java.
I've not worried a whole lot about "JavaBeans," but I have found that following basic JavaBean conventions has been very helpful for me in the past: basically, using standard getters and setters for properties. Turns out there's a JavaBean convention I was unaware of which is really going to help here: bound properties. Bound properties are properties available through standard getters and setters which fire PropertyChangeEvents when they change. [I don't know for sure, but the JavaBeans standard may specify that all properties are supposed to be "bound properties." Not relevant to me, at this point. Be aware also that "standard" getters and setters can be very non-standard through the use of BeanInfo classes to define a JavaBean's exact interface, but I never use that, either.] (The main other JavaBean convention that I choose to follow or not as appropriate in each situation is a no-argument constructor; I'm already following it in this project because each of these Backend objects has to be serializable.)
I've found this blog entry, which was very helpful in cluing me into the bound properties/PropertyChangeEvents issue and helping me construct a plan for how I'm going to rework this code.
Right now all of my backend objects inherit from a common class called Model, which provides a couple of things every backend in this system needs including serialization support. I'm going to create an additional class JavaBean as a superclass of Model which will provide the PropertyChangeEvent support that I need, inherited by every Model. I'll update the setters in each Model to fire a PropertyChangeEvent when called. I may also have JavaBean inherited by a couple of classes which aren't technically Models in the same sense as these but which could also benefit from having other classes registered as listeners for them. The JavaBean class may not fully implement the JavaBean spec; as I've said, there are several details I don't care about. But it's good enough for this project. It sounds like I could get all this by inheriting from java.awt.Component, but these aren't components in any sense that I can justify, so I don't want to do that. (I also don't know what overhead it might entail.)
Once every Model is a JavaBean, complete with PropertyChangeEvent support, I'll do a lot of code cleanup: Models that are currently keeping references to Panels will be updated and the Panels will register themselves as listeners. So much cleaner! The Model won't have to know (and shouldn't have known in the first place) what methods the Panel should call on itself when the property updates.