Need help with application design (MVC, classes etc.) - objective-c

I'm pretty new to object oriented programming (do have scripting knowledge in PHP and Posix shell programming) and I'm working on a beer recipe application. I've already started the project, but I guess the design is not that good from a MVC point of view. I hope you will help me get the design right. Here are a couple of things to know about the application.
The application needs to be a Document Based Application (open/save recipes in Beer XML). The main window has several textfields to set information like: name, beertype, volume etc. Then there are a couple of tableviews with arrays for: malts, hops and spices, each having their own sheet for adding values.
How should I make my classes? Like this?
NSDocument class (with the open/save XML code)
(3x) NSWindowController (for each sheet: malts, hops, spices)
(3x) NSArrayController (for each tableview: malts, hops, spices)
Should the arrays, managed by the NSArrayController objects, be separate classes (in a MVC perspective (as Model)) or should they be incorporated into their NSArrayController class?

I would start by brushing up on a couple of Apple provided docs:Object-Oriented Programming with Objective-C and Cocoa Fundamentals Guide.
I would also look at using Core Data. With relatively little implementation you have a very powerful data structure (the M in MVC) that is easy to implement with your view and view controllers (the V & C):
Core Data Programming Guide
I highly recommend reading these. They are not bad reads and you gain a TON of knowledge. Apple docs are really the best.
Good luck.

Assuming that these are your requirements,
Editor application that uses xml (beerxml) as it datasource.
Viewer that shows the available data (in a tabular format or as sheets)
User can add/remove/edit entries in each xml
There exists a relationships between the xmls (datasources) (unsure...)
Before applying any design pattern, you should start applying the basic OOP concepts to identify and create classes (state and behavior) and define the relationship between the classes.
For example, receipes.xml is used to denote the recipes used to manufacture a product. To design a class for this go through the xml. You can identify the following data classes (objects i.e. instances of classes represent a real world entity, while the class is more like a template/blue print for the object):
Recipe (main class)
Hop
Fermentable
Yeast
Water
Style
Equipment
Mash
MashStep
and so on.
Once you have identified the classes that form your data model (information repository), identify the properties and behavior of each class. For example, the Yeast class would contain the properties, Name, Version, and so on. Do not worry about the type of the property (string, integer, etc.).
To identify the controllers, view the application from the point of view of the user. What are the use cases (what does the user do with the application? Edit? Add? etc.). These use cases will inadvertently require processing information in a particular flow (sequence). The information is available in your model classes. The controller will invoke operations on the model classes and determine the interaction between them.
For example, suppose there is a use case that the use needs to add a new yeast to the system. Then the controller would create a new instance of the Yeast class and populate it with values supplied by the user (after performing some sort of validation). The created yeast would then be added to the ListOfAvailableYeasts and made available to other classes.
The view is (as the name suggests), a user interface to your data. In MVC, the view is usually updated by an observer that monitors the model for changes and updates the UI accordingly (there are several variation to MVC pattern).
The main point here is that you should first focus on object orientation design first rather than jumping directly into the design patterns.
If you need some guidelines on how to create classes from the xml, then take a look at the xsd.exe tool. You can generate the xsd (xml schema) from an xml and then use this xsd to generate a class hierarchy for the xml (I suggest you start with recipes.xml). You can modify the generated classes to your requirement.
The generated classes would look something like this,
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class RECIPESRECIPE {
private string nAMEField;
private string vERSIONField;
private string tYPEField;
private string bREWERField;
private string aSST_BREWERField;
private string bATCH_SIZEField;
...
}
Hope that this is sufficient to get you started.

Related

A few general questions about Service Reference and MVVM pattern

There is a web service.
It provides types Zoo and Animal.
Zoo has a dictionary of animal ids and names.
Animal has properties: Id, Name and (additional stuff).
It has a method GetZoo that returns a zoo object.
It has a method GetAnimalStuffById that returns an Animal object with Id, Name and the (additional stuff).
So the idea is - GetZoo allows me to get a list of animal ids + names, and then GetAnimalStuffById fetches full animal info.
I add a "service reference" to that service in VS and want to write a MVVM app. Some things I don't fully understand and need to be brainwashed about.
Is it OK for autogenerated classes to be my models?
Not related to the example, but anyway: what "collection type" should I specify when adding service reference? Is ObservableCollection an overkill and a bad practice for models?
Say, user goes to an application page showing full animal info. Obviously, initially I have an AnimalViewModel with only Id and Name values (taken from GetZoo). As the page is navigated to, I call GetAnimalStuffById and get an Animal object with all the data. What should I do next? Replace the DataContext of my view with a new AnimalViewModel created from new Animal object (A), or just replace the values in it (B)?
If the answer is (A), how do I replace the DataContext in all the views?
If the answer is (B), what should cause that update? Should the VMs subscribe to some fancy manager's event about getting an Animal update? Or is there some other approach?
What is the purpose of INotifyPropertyChanged in the autogenerated classes? They are always returned fresh from the webservice in my case. Does Microsoft suggest to use them also as ViewModels in some scenarios?
Thanks.
Here are a few answers based on my own experience with MVVM (which may or may not be "best practice"..)
Absolutely! No need to do everything twice - see #5 and #6 (although there are people who disagree here).
Yes, unless you actually need the functionality of an ObservableCollection server-side, I would say it's overkill, and possibly confusing to others. Techincally, there's no overhead to the messages being sent across the wire, but I would go with something simpler, like an array.
Go with option B.
-
For example, you could have a single property in your AnimalViewModel to hold all the additional stuff: public Animal AdditionalData { .... Now, whoever calls GetAnimalStuffById can just update the current ViewModel's AdditionalData with that Animal object.
I assume you already know that INotifyPropertyChanged is there to let the View know that some data has changed somewhere (if not, googling "inotifypropertychanged mvvm" should get you started). Now, connecting the dots from #1 and #5, your View can now bind to the animal's additional data by going through the AdditionalData property without having to recreate everything in the ViewModel: <TextBox Text="{Binding Path=AdditionalData.HeightOrWhatever}" />.
Note: If your View isn't WPF or Silverlight, that last point won't make much sense..
And here's answers based on my experience (mainly to provide another point of view)
It's fine to autogenerate Models from an endpoint. But I would recommend POCO Models without any INPC cruft. Two reasons, a) it makes the Models simpler and easier to maintain and b) You won't be tempted to expose your Models directly to the View, or if you do they won't work properly.
Continuing on from #1, I would not use ObservableCollection in Models. Again to keep things simple and to avoid presenting Models directly to the View.
Option (B)
-
All the properties in the ViewModel should implement INPC. Then when you change them the binding will automatically update. You can either have all the AdditionalData values as properties of your AnimalViewModel which is flattening the data, or you can have an AdditionalDataViewModel object to hold the extra data. To map data from an AdditionalData object to AdditionalDataViewModel consider using a mapping tool like AutoMapper or ValueInjecter.
I don't know why the autogenerator added INPC stuff into your models. What tool are you using? In any case as I've said I do not recommend having INPC in Models, or exposing Models to the View. Instead you should be mapping from Models to ViewModels and only exposing ViewModels to the View.

Inserting controller logic between model and view when using Interface Builder, NSObjectController sub-classes, and bindings

I've been struggling to understand the best way to insert controller logic when using IB, NSObjectController sub-classes and bindings.
I need to insert controller logic between the model and the view, and I'm struggling to find an elegant way to do so. Yes, you can send actions to the file owner and handle controller logic in there, but when some core data models can extend across fifty entities or more with deep relationship structures, this starts to mount up to an incredible amount of boiler-plate code.
A very simplified example would be this; imagine you have an entity with four string attributes myTextWinter, myTextSpring, myTextSummer, myTextAutumn. You have a view which connects to this in IB via an NSObjectController. Now, say the user can select which 'Season' they wish to view by choosing Spring, Summer, Autumn, Winter from a Menu somewhere - when that season is selected, I would like to display the appropriate season's text.
In this simplified example I could probably fetch the object in the NSDocument sub-class, create a property called mySeasonText which I bind to in my view, and then check my NSUserDefaults for the appropriate season and route the requests to the appropriate attribute in the model.
The problem comes when I have fifty entities, some with relationships some two, three or more deep, each with their own set of season specific text attributes that I wish to switch between when selecting from the Season menu. Or if I have a bunch of nsarraycontrollers chained together to access objects at a deeper, and deeper level.
To date, I've been doing the following; adding a property in each of my model objects called 'mySeasonText', then grabbing the setting from my controller setting, and routing to the appropriate season. I refresh these objects whenever a new item in the menu is selected.
Whilst this works and eliminates an absolute ton of boiler-plate code, my controller logic is now in my model.
There must be a better way! Could someone please point me in the correct direction?
This is a tricky topic. Apple even mentions these challenges in its own documentation:
By using the bindings technology, you can easily create a Cocoa MVC application whose views directly observe model objects to receive notifications of state changes. However, there is a theoretical problem with this design. View objects and model objects should be the most reusable objects in an application. […] Design-wise, it's best to keep model and view objects separate from each other, because that enhances their reusability.
The design pattern you are looking for is a Mediating Controller - a way to use the cocoa-bindings classes to insert controller logic:
Mediating controllers are typically ready-made objects that you drag from the Interface Builder library. You can configure [Mediating controllers] to establish the bindings between properties of view objects and properties of the controller object, and then between those controller properties and specific properties of a model object. As a result, when users change a value displayed in a view object, the new value is automatically communicated to a model object for storage—via the mediating controller; and when a property of a model changes its value, that change is communicated to a view for display.
Here is how I like to think of them: Have you ever seen a movie or TV show where two characters need to talk, but they don't speak any of the same languages? They find someone else (or in a comedy 5 other people) who each have one language in common, and they communicate by playing a giant game of translation telephone.
Mediating controllers are kind of like that.
As your application grows they learn all the super specific rules about where to look for this one thing on this one view. This is the kind of code that an app needs to run, but you rightly feel that it is nasty when put in your model.
For several specific and detailed examples, Apple provides this amazingly detailed document: Bindings Message Flow.
For some really good discussions about this and related MVC + Bindings please see:
MVC and cocoa bindings best practices question
Why use NSObjectController?
Replacing model objects using an NSArrayController

One large class compared to several small classes for a Cocoa Mac application

I have created an application, using ARC, that parses data from an online XML file. I am able to get everything I need using one class and one call to the API. The API provides the XML data. Due to the large xml file, I have a lot of variables, IBOutlets, and IBActions associated with this class.
But there are two approaches to this:
1) create a class which parses the XML data and also implements that data for your application
, i.e. create one class that does everything (as I have already done)
or
2) create a class which parses the XML data and create other classes which handle the data obtained from the XML parser class, i.e. one class does the parsing and another class implements that data
Note that some APIs that provide XML data track the number of calls/minute or calls/day to their service. So you would not want several classes calling the API, it would be better to make one request to the API which receives all the data you need.
So is it better to use several smaller classes to handle the xml data or is it fine to just use one large class to do everything?
When in doubt, smaller classes are better.
2) create a class which parses the XML data and create other classes which handle the data obtained from the XML parser class, i.e. one class does the parsing and another class implements that data
One key advantage of this is that the thing that the latter class models is separate from the parsing work that the former class does. This becomes important:
As Peter Willsey said, when your XML parser changes. For example, if you switch from stream-based to document-based parsing, or vice versa, or if you switch from one parsing library to another.
When your XML input changes. If you want to add support for a new format or a new version of a format, or kill off support for an obsolete format, you can simply add/remove parsing classes; the model class can remain unchanged (or receive only small and obvious improvements to support new functionality in new/improved formats).
When you add support for non-XML inputs. For example, JSON, plists, keyed archives, or custom proprietary formats. Again, you can simply add/remove parsing classes; the model class need not change much, if at all.
Even if none of these things ever happen, they're still better separated than mashed together. Parsing input and modeling the user's data are two different jobs; mashing them together makes them hard or impossible to reason about separately. Keep them separate, and you can change one without having to step around the other.
I guess it depends on your application. Something to consider is, what if you have to change the XML Parser you are using? You will have to rewrite your monolithic class and you could break a lot of unrelated functionality. If you abstracted the XML parser it would just be a matter of rewriting that particular class's implementation. Or what if the scope of your application changes and suddenly you have several views ? Will you be able to reuse code elsewhere without violating the DRY (Don't repeat yourself) principle ?
What you want to strive for is low coupling and high cohesion, meaning classes should not depend on each other and classes should have well defined responsibilities with highly related methods.

How to access a class from another class?

I’m fairly new to OO. If I have two classes A and B that need to exchange data, or call each other’s methods, I need to be able to access an instance of class B from class A. Should I maintain the address of the instance object in a global variable? Should I appoint a (singleton) master class, and make (pointers to) instances of A and B properties of the master class? (AppDelegate comes to mind.)
Is there a straightforward by-the-book way to implement this? Somehow I‘m missing some "best practice" here. I’ve looked through Apple's examples, but didn't find an answer.
EDIT: Since I'm fairly new to MVC design patterns, my question is essentially "Who creates who"?
We're talking about an Audio Player here. 1. When the user selects a song, the UI displays its waveform by creating a viewController which creates the appropriate view. 2. When the user hits play, the UI displays a timeline while the song is playing by overlaying a new view over the waveform. Now, the latter view needs some info from the waveform display viewController. Right now, I'm storing a pointer to the viewController in an instance variable of my appDelegate. This works, but feels extremely strange.
Should I outsource the info that is needed by both classes to some third entity that every class can access easily?
Classes aren't simply departments of code. They are templates for the creation of objects, which you should think of as actors in your program, doing things within their areas of responsibility (which you define—you decide what each object does) and interacting with each other.
While you can handle a class as you would an object, classes generally do not talk to each other. Most of the time, you will create and use instances of the classes—which is what we normally mean by “objects”—and have those talking to each other. One object sends another a message, telling the receiver to do something or changing one of the receiver's properties. These messages are the interactions between your program's objects.
Those weird expressions in the square brackets are message expressions. Nearly everything you'll do with a class or object will involve one or more messages. You can send messages to classes the same as to objects, and classes can send messages just as objects can.
In Cocoa and Cocoa Touch, you typically have model objects, view objects, controller objects, data objects (such as NSString, NS/UIImage, and NSURL), and helper objects (such as NSFileManager). The classes you'll write for your application will mainly be model, view, and controller objects (MVC). The model represents (models) what the user will see themselves manipulating; the view displays the model to the user; the controller implements logic and makes sure the model gets saved to and loaded from persistent storage.
For more information, see Object-Oriented Programming in Objective-C and the Cocoa Fundamentals Guide.
Since I'm fairly new to MVC design patterns, my question is essentially "Who creates who"?
Controllers create and load the model, and load the views, and pass the model to the view for display. Certain controllers may also create other controllers.
It's good to keep a straightforward tree-like graph of ownership from a single root of your program—typically the application object—down through controllers to leaf objects in the models and views. If two objects own each other, that's a problem. If an object is not owned by anything outside of its own class (a singleton), that's usually a problem as well—a sign you need to think some more about where that code belongs. (Helper objects are the main exception; most of those are singletons. Again, see NSFileManager for an example. But they are few and far between.)
Further situation analysis require more information. At first place you should more specify the relation between classes and what exactly do you mean by exchanging data.
Singletons should be generally avoided. If you want to exchange information it is usually sufficient to provide for example instance of the class A to the instance of the class B by some method or constructor. The instance of B is then capable of calling public methods (and accessing public properties) of the instance of A.
A little bit of "best practices" can be learn by searching up "Design Patterns".
You should decide if one class can be an object of another class (encapsulation), or if one class can inherit from the other class (inheritance). If neither of these is an option, then maybe you could make one class (or some of its members) static?
Thanks for your contributions. Additionally, I found information on this page very useful. It lays out MCV considerations for cocoa in a hands-on way and practical language.

How to prevent multiple classes for the same business object?

A lot of the time I will have a Business object that has a property for a user index or a set of indexes for some data. When I display this object in a form or some other view I need the users full name or some of the other properties of the data. Usually I create another class myObjectView or something similar. What is the best way to handle this case?
To further clarify:
If I had a class an issue tracker and my class for an issue has IxCreatedByUser as a property and a collection of IxAttachment values (indexes for attachment records). When I display this on a web page I want to show John Doe instead of the IxCreatedByUser and I want to show a link to the Attachment and the file name on the page. So usually I create a new class with a Collection of Attachment objects and a CreatedByUserFullName property or something of that nature. It just feels wrong creating this second class to display data on a page. Perhaps I am wrong?
The façade pattern.
I think your approach, creating a façade pattern to abstract the complexities with multiple datasources is often appropriate, and will make your code easy to understand.
Care should be taken to create too many layers of abstractions, because the level of indirection will ruin the initial attempt at making the code easier to read. Especially, if you feel you just write classes to match what you've done in other places. For intance if you have a myLoanView, doesn't necessarily you need to create a myView for every single dialogue in the system. Take 10-steps back from the code, and maybe make a façade which is a reusable and intuitive abstraction, you can use in several places.
Feel free to elaborate on the exact nature of your challenge.
One key principle is that each of your classes should have a defined purpose. If the purpose of your "Business object" class is to expose relevant data related to the business object, it may be entirely reasonable to create a property on the class that delegates the request for the lookup description to the related class that is responsible for that information. Any formatting that is specific to your class would be done in the property.
Here's some guidelines to help you with deciding how to handle this (pretty common, IMO) pattern:
If you all you need is a quickie link to a lookup table that does not change often (e.g. a table of addresses that links to a table of states and/or countries), you can keep a lazy-loaded, static copy of the lookup table.
If you have a really big class that would take a lot of joins or subqueries to load just for display purposes, you probably want to make a "view" or "info" class for display purposes like you've described above. Just make sure the XInfo class (for displaying) loads significantly faster than the X class (for editing). This is a situation where using a view on the database side may be a very good idea.