Welcome to the Hotel!
The Hotel pattern is a UI pattern I've started using based off a few things. A big one is my disdain of existing UI pattern and the poor Object Oriented Design patterns they encourage and fascilitate. Another is the focus on software craftsmanship and XP practices. My XP practice includes Extreme Encapsulation. Many existing UI patterns are testable but they violate best practices and Object Oriented Design. Another aspect that stands out is that they aren't from emergent architecture. While I have some preconceived notions around UI patterns; the Hotel is the pattern I consistently get when I'm TDDing a UI layer. It is what I get when I practice emergent design and best practices.
I've dubbed this the Hotel Pattern to provide an apt metaphor when communicating about it. The names give each component a very specific task. When objects and layers can be supported in their focus by the names we give them; the better the code will emerge. The longer before it becomes crufty. This is a renaming of the View Bridge Mediator pattern I've written of and have been demonstrating. I find the Hotel Metaphor much better to communicate the intent of the layers.
There are three components to the Hotel pattern.
- Room - Interaction with consumers
- Bellhop - The communication
- Concierge - Access to the world
The Room
The room is where the user interacts. User being whatever the consumer is. With a UI layer; the user is an actual user interacting with the UI; and that's where I encourage a much stricter Hotel pattern naming. I use this pattern style in non-UI modules, but not as strictly. In pure code classes/modules, it's easier to maintain the extremem encapsulation and object oriented design. They should be free to follow other naming and metaphor conventions.
Given that that this is primarily a UI pattern, I'll talk about it solely as a UI pattern. It'll simplify the explanation for this post.
The Room's job is to communicate internal widgets. There's kinda two things; and I haven't found a good way to break them out, so for now; stuck as a single class doing "two" things.
The first is to communicate the widget that maps to a type of information display. If we want to have a widget to display a name, the Room knows what widget maps to displaying the name.
The simple form of this is that if there's a label to display a name; the Room will have a method to return a widget for that display.
public class MyRoom : PlatformView{
public MyWidget Name(){
return _myWidgetForName;
}
}
This allows the UI to change around a lot and no one else will be affected. No logic will be affected in the rest of the system. One small caveat to this is that my (Interface Resolution MixIn)[GET LINK] is strongly supporting the ability to have the UI decoupled from the consumer. It's the simplest way I've seen, working with this pattern, to maintain a clean architecture.
Clearly, I highly advocate these things. :)
These methods are not defined by the Room. These exist for the next layer down, the Bellhop. The Room implements an interface defined by the Bellhop. This drives the clean architecture.
The other component of the room's widget communication is event handling. The room will have the methods the widget invokes; and immediately pass on the data to the Bellhop.
public class MyRoom : PlatformView{
public void MyWidgetForName_SomeEvent(args){
_myBellhop.SomeEventForName(args, more args);
}
}
The room is responsible for communicating internal widget events.
The job of widget communication is all the Room does. That's it's job.
One of the metaphors that drive the Hotel theme is that the events are "requests" from the user of the room. We'll ignore the invention of the phone and pretend the next layer is required for all communication. :)
The Bellhop
The Bellhop is responsible for bringing all requests down from the room. It's also how things are brought to, and placed in, the Room. The Bellhop defines the name of widgets that can be interacted with. The Bellhop.Widgets interface will define the "Name" method. The bellhop will know what to request of the room, and the room provides it.
As part of this interface, the Bellhop can only do so many things. The Bellhop defines all of the events that can be handled. If it's not a method on the Bellhop.Requests, then it can't be requested of the Bellhop.
This is a little bit of an interface explosion; but it helps both TDD and Clean Architecture. These have been huge wins in my experience, so I advocate their usage. Clearly not a requirement... but my heavy preference.
To get the data, the Bellhop has to interact with the Concierge.
The Concierge
The Concierge knows where to get everything. The concierge, much more than the other two layers, is likely to involve many classes. Overall, if it's app or system access required FOR THE ROOM; knowledge of where that data comes from belongs with the Concierge.
The Concierge provides the interface for the Bellhop, Concierge.Packages, which define all the types of data that the Bellhop can get from the Concierge. The Concierge also defines it's own Requests interface that provides the Bellhop a way to request things from the rest of the world.
The Concierge's job is to know where to provide any and all data required by the view.
A big part of the Concierge's responsibilities is to take anything that may need decisions made and make the decision before giving it to the Bellhop. This is generally in the form of one of the patterns that remove if's and switches. This allows the bellhop and room to just DO. No decisions need to be made; they just work; Simple UI layers.
Summary
This is the high level overview of the hotel pattern. Earlier posts on the evolution of this idea has more of the details and intent behind the pattern. This is largely an update around the metaphor for it. Having a good metaphor is important for software development. As I've worked with this pattern and the naming for it; I've evolved what it is.
This helps it make more sense in my head and allows me to more effectively communicate what I'm thinking/doing. There's still a bit of "Why a new pattern, there's plenty already", but this is different in how it supports the best practices all the way to the UI layer. It minimizes violation of best practices due to being a "book end".