Model-View-Presenter
In MVP, the Presenter contains the UI business logic for the View. All invocations from the View delegate directly to the Presenter. The Presenter is also decoupled directly from the View and talks to it through an interface. This is to allow mocking of the View in a unit test. One common attribute of MVP is that there has to be a lot of two-way dispatching. For example, when someone clicks the "Save" button, the event handler delegates to the Presenter's "OnSave" method. Once the save is completed, the Presenter will then call back the View through its interface so that the View can display that the save has completed.
MVP tends to be a very natural pattern for achieving separated presentation in WebForms. The reason is that the View is always created first by the ASP.NET runtime. You can find out more about both variants.
Two primary variations
Passive View: The View is as dumb as possible and contains almost zero logic. A Presenter is a middle man that talks to the View and the Model. The View and Model are completely shielded from one another. The Model may raise events, but the Presenter subscribes to them for updating the View. In Passive View there is no direct data binding, instead, the View exposes setter properties that the Presenter uses to set the data. All state is managed in the Presenter and not the View.
- Pro: maximum testability surface; clean separation of the View and Model
- Con: more work (for example all the setter properties) as you are doing all the data binding yourself.
Supervising Controller: The Presenter handles user gestures. The View binds to the Model directly through data binding. In this case, it's the Presenter's job to pass off the Model to the View so that it can bind to it. The Presenter will also contain logic for gestures like pressing a button, navigation, etc.
- Pro: by leveraging data binding the amount of code is reduced.
- Con: there's a less testable surface (because of data binding), and there's less encapsulation in the View since it talks directly to the Model.
Model-View-Controller
In the MVC, the Controller is responsible for determining which View to display in response to any action including when the application loads. This differs from MVP where actions route through the View to the Presenter. In MVC, every action in the View correlates with a call to a Controller along with an action. In the web, each action involves a call to a URL on the other side of which there is a Controller who responds. Once that Controller has completed its processing, it will return the correct View. The sequence continues in that manner throughout the life of the application:
Action in the View
-> Call to Controller
-> Controller Logic
-> Controller returns the View.
One other big difference about MVC is that the View does not directly bind to the Model. The view simply renders and is completely stateless. In implementations of MVC, the View usually will not have any logic in the code behind. This is contrary to MVP where it is absolutely necessary because, if the View does not delegate to the Presenter, it will never get called.
Presentation Model
One other pattern to look at is the Presentation Model pattern. In this pattern, there is no Presenter. Instead, the View binds directly to a Presentation Model. The Presentation Model is a Model crafted specifically for the View. This means this Model can expose properties that one would never put on a domain model as it would be a violation of separation-of-concerns. In this case, the Presentation Model binds to the domain model and may subscribe to events coming from that Model. The View then subscribes to events coming from the Presentation Model and updates itself accordingly. The Presentation Model can expose commands which the view uses for invoking actions. The advantage of this approach is that you can essentially remove the code-behind altogether as the PM completely encapsulates all of the behavior for the view. This pattern is a very strong candidate for use in WPF applications and is also called Model-View-ViewModel.
There is a MSDN article about the Presentation Model and a section in the Composite Application Guidance for WPF (former Prism) about Separated Presentation Patterns
The blog post you quoted overstates its claim a bit. FP doesn't eliminate the need for design patterns. The term "design patterns" just isn't widely used to describe the same thing in FP languages. But they exist. Functional languages have plenty of best practice rules of the form "when you encounter problem X, use code that looks like Y", which is basically what a design pattern is.
However, it's correct that most OOP-specific design patterns are pretty much irrelevant in functional languages.
I don't think it should be particularly controversial to say that design patterns in general only exist to patch up shortcomings in the language.
And if another language can solve the same problem trivially, that other language won't have need of a design pattern for it. Users of that language may not even be aware that the problem exists, because, well, it's not a problem in that language.
Here is what the Gang of Four has to say about this issue:
The choice of programming language is important because it influences one's point of view. Our patterns assume Smalltalk/C++-level language features, and that choice determines what can and cannot be implemented easily. If we assumed procedural languages, we might have included design patterns called "Inheritance", "Encapsulation," and "Polymorphism". Similarly, some of our patterns are supported directly by the less common object-oriented languages. CLOS has multi-methods, for example, which lessen the need for a pattern such as Visitor. In fact, there are enough differences between Smalltalk and C++ to mean that some patterns can be expressed more easily in one language than the other. (See Iterator for example.)
(The above is a quote from the Introduction to the Design Patterns book, page 4, paragraph 3)
The main features of functional
programming include functions as
first-class values, currying,
immutable values, etc. It doesn't seem
obvious to me that OO design patterns
are approximating any of those
features.
What is the command pattern, if not an approximation of first-class functions? :)
In an FP language, you'd simply pass a function as the argument to another function.
In an OOP language, you have to wrap up the function in a class, which you can instantiate and then pass that object to the other function. The effect is the same, but in OOP it's called a design pattern, and it takes a whole lot more code.
And what is the abstract factory pattern, if not currying? Pass parameters to a function a bit at a time, to configure what kind of value it spits out when you finally call it.
So yes, several GoF design patterns are rendered redundant in FP languages, because more powerful and easier to use alternatives exist.
But of course there are still design patterns which are not solved by FP languages. What is the FP equivalent of a singleton? (Disregarding for a moment that singletons are generally a terrible pattern to use.)
And it works both ways too. As I said, FP has its design patterns too; people just don't usually think of them as such.
But you may have run across monads. What are they, if not a design pattern for "dealing with global state"? That's a problem that's so simple in OOP languages that no equivalent design pattern exists there.
We don't need a design pattern for "increment a static variable", or "read from that socket", because it's just what you do.
Saying a monad is a design pattern is as absurd as saying the Integers with their usual operations and zero element is a design pattern. No, a monad is a mathematical pattern, not a design pattern.
In (pure) functional languages, side effects and mutable state are impossible, unless you work around it with the monad "design pattern", or any of the other methods for allowing the same thing.
Additionally, in functional languages
which support OOP (such as F# and
OCaml), it seems obvious to me that
programmers using these languages
would use the same design patterns
found available to every other OOP
language. In fact, right now I use F#
and OCaml everyday, and there are no
striking differences between the
patterns I use in these languages vs
the patterns I use when I write in
Java.
Perhaps because you're still thinking imperatively? A lot of people, after dealing with imperative languages all their lives, have a hard time giving up on that habit when they try a functional language. (I've seen some pretty funny attempts at F#, where literally every function was just a string of 'let' statements, basically as if you'd taken a C program, and replaced all semicolons with 'let'. :))
But another possibility might be that you just haven't realized that you're solving problems trivially which would require design patterns in an OOP language.
When you use currying, or pass a function as an argument to another, stop and think about how you'd do that in an OOP language.
Is there any truth to the claim that
functional programming eliminates the
need for OOP design patterns?
Yep. :)
When you work in a FP language, you no longer need the OOP-specific design patterns. But you still need some general design patterns, like MVC or other non-OOP specific stuff, and you need a couple of new FP-specific "design patterns" instead. All languages have their shortcomings, and design patterns are usually how we work around them.
Anyway, you may find it interesting to try your hand at "cleaner" FP languages, like ML (my personal favorite, at least for learning purposes), or Haskell, where you don't have the OOP crutch to fall back on when you're faced with something new.
As expected, a few people objected to my definition of design patterns as "patching up shortcomings in a language", so here's my justification:
As already said, most design patterns are specific to one programming paradigm, or sometimes even one specific language. Often, they solve problems that only exist in that paradigm (see monads for FP, or abstract factories for OOP).
Why doesn't the abstract factory pattern exist in FP? Because the problem it tries to solve does not exist there.
So, if a problem exists in OOP languages, which does not exist in FP languages, then clearly that is a shortcoming of OOP languages. The problem can be solved, but your language does not do so, but requires a bunch of boilerplate code from you to work around it. Ideally, we'd like our programming language to magically make all problems go away. Any problem that is still there is in principle a shortcoming of the language. ;)
Best Answer
Pshew... this might be a long answer... but here goes...
First, let's start with this statement:
Maybe this doesn't even make sense in C because of the lack of formal OOP language constructs?
Couldn't disagree more with that statement. As I'll show later on; just because C doesn't have nifty keywords like "class" doesn't mean you can't accomplish the same things.
I'll try to go through this step-by-step as best I can - following your question's flow.
OOP in C
I suspect, based on the phrasing of your question, that you have a pretty decent grasp of OOP concepts (you're even thinking in terms of patterns and even have a good idea of how those patterns will play out for your particular scenario) - so let me do an "OOP in C" tutorial in "30 seconds or less".
Once you get the hang of things you'll realize there is a lot more you can do than what I'm going to show here - but I just want to give you a taste.
101
First, we'll start with a basic "class" (go with me on this):
Foo.h:
Foo_Internal.h: (you'll see why I broke this out in a second)
Foo.c:
Couple things to notice:
Foo
behind an opaque pointer. Other people don't know what is in aFoo
because that implementation detail is in the "internal" header file, not the "public" header.Inheritance
So what if we want a "subclass" of
Foo
- which only adds additional functionality - but can be substituted for aFoo
? Simple:FooSubclass.h:
FooSubclass_Internal.h:
FooSubclass.c
Now, I should mention, just like we made "initializers" which don't actually call
malloc
, but are responsible for initializing the member variables - we also really need deallocators - which don't actually free the struct - but instead free/release any "owning" references, etc. However... I'm actually going to mention something in the section below which might explain why I didn't bother with that yet.You should notice now - that since our
FooSubclass
's first member is, in fact, aFoo
struct - that any reference to aFooSubclass
is also a valid reference to aFoo
- meaning it can be used as such pretty much anywhere.However, there are a few small issues with this - like I mentioned in the paragraph before last - this technique doesn't actually let you change behavior of the base class. (Something we'd like to do for deallocating our instance, for example).
Polymorphism
Let's say we have some method - we'll come up with a random BS example - called
calculate
.We want calling
calculate
on aFoo
to return one value - but a different value if it was called on aFooSubclass
.This is simple in C - it's really just a matter of creating a wrapper method which actually calls a function referenced by a function pointer. OOP languages do this for you behind the scenes and it's usually implemented via what's referred to as a VTable.
Here's an example (I'm going to stop giving complete examples and instead focus on the relevant parts):
First we define the signature of the method. Here we're saying "calculateMethod" is: a pointer to a method which takes one parameter (a pointer) and returns an int.
Next, we add a member variable in our base class which will point to some function:
We initialize this with some initial value in the
FooInitialize
method (for our base implementation):Now we make some way for subclasses to override this method - say, for example, a method declared in the
Foo_Internal.h
file calledvoid FooSetCalculateMethod(Foo * this, calculateMethod value);
- and voila! Methods which can be overridden in subclasses.Model
Our model would typically consist of data acquisition from Analog to Digital converters in the product.
OK - so, Model is probably the easiest thing to implement - simple "classes" which are used as data storage mechanisms.
You'll have to figure something out for your particular scenario (being an embedded system I'm not sure what your exact restrictions will be - and if you're worried about RAM / persistence / etc) - but I think you don't want me to dive into that anyways.
View
The views might be a web page powered by an embedded web server, or else an LCD screen with capacitive touch control.
For physical things your "view" may be fixed buttons on a control panel - or, like you said, it could be an LCD or HTML.
The bottom line here is you simply need classes which are capable of presenting the rest of your system with a "simple" interface for displaying/changing things in the view - and encapsulate the details of IO to the user.
Typically the "I" part of "IO" needs at least some small wedge of code in the view.
I don't think this is ideal - but, most of the time, there isn't a good way around having your "view" proxy user input back to your controllers. Maybe with your system there is a good way around this - given you have total control.
I hope you can see now how you could easily go about creating some view classes which are relevant to your needs.
Controller
Our controllers would more or less be the glue logic that manages the relationship between these two areas of code.
This is usually the guts of the application. You'll likely need more than one controller around at a given time - one for ingress/processing of sensor data, one or more for whatever UI you've got active, and possibly others.
Anyways, I hope that helps... I feel like I'm writing a book now, so I'll stop.
Let me know if you want more, or if that helps at all.