Re: Text terminal rendering design
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Mon, 21 May 2007 17:51:48 GMT
Responding to Guild...
The client should NEVER be knowingly invoking methods of your UI objects.
I guess that you are speaking figuratively here. If the client cannot invoke methods of any object in my subsystem, how can it send messages to my subsystem? I infer that there is a facade object that the client can invoke methods on and using poetic licence we are not calling it an object.
The client sends a message to your UI interface. Your UI interface then re-dispatches that message to some method in your
UI. But the client should have no idea what method, if any,
responds to the message.
This all sounds a lot like exactly what my current design already does, so I would take it as confirmation of the quality of my design, but for one detail. The issue that I think might be important is that I do not quite fallow the GoF facade pattern in that my facade is made of multiple objects.
What I was responding here was, "The client will inevitably have to call methods of my objects, but thanks to encapsulation that is the limit of the clients knowledge." As I read that statement the client is calling specific object methods in your UI software. If that is not the case, fine. But I think there is another disconnect...
Specifically, I have both a Terminal class and a SymbolFactory class and all objects of both classes act as a combined facade for the subsystem. I cannot see any harm in this design. Just because the client invokes a method on a particular factory does not mean the client knows even one detail about what happens in response to that message. Correct me if I am wrong.
Terminal and SymbolFactory are part of the interface Facade?!?
Typically the subsystem interface (or application's programmatic API) is a Facade pattern object. (The interface may even be composed of multiple Facade objects.) But those objects implement the subsystem /interface/, not the subsystem itself. The subsystem itself is implemented with objects like Terminal and SymbolFactory that the subsystem interface hides completely from the outside world.
In the GoF structure diagram on pg. 187 the "Facade" box represents an object that provides the interface to the outside world (e.g., to Client). Its implementation understands the way the subsystem is constructed and provides appropriate dispatching of messages to objects within the subsystem.
I would expect Terminal and SymbolFactory to objects /within/ the subsystem boundary that the Facade object talks to. They both seem like problem space entities that are unique to the subject matter. Those objects would not be visible at all to Client.
An alternative would be for the client to request a specific factory by a factory ID that is passed in as data, but I can see only a slight increase in complexity and no benefit at all from that.
It's all a matter of
bigFacade.createSymbol(factory,symbolData);
versus
factory.createSymbol(symbolData);
Why should I or the client or anyone care which is used? I'm exposing the existence of a factory object with certain methods, but that is no worse than exposing the existence of a facade object. I expect that you see some sort of mess resulting from the second way, but I need that mess to be illustrated clearly before I will be able to see it.
In all this I have ignored the Symbol objects because they are mere data objects and not worthy of all the discussion we have been having over them. They only exist to be passed around in messages as part of the data, even in my current design.
The subject matter of your software (as I understand it) is to provide rendering of symbols on display terminals for clients in an manner that isolates the client from rendering issues on particular terminals.
As such the interface that subject matter provides to the client should be as generic as the client's view of display. So I would expect the interface to be at the level of requests like:
Display icon (id)
Change icon color (id, color)
Save new icon (id, ...)
IOW, the client is messing with icons and wants to think of them at that level of abstraction. The client invokes your UI service to display those icons precisely because it doesn't care or want to know how display is done.
It is the job of the Facade object that implements the UI interface to interpret those requests in terms of the display subject matter implementation and figure out who should respond to them.
The interface provides two-way decoupling. The client can't know
about objects in your subsystem, so it can't talk to them
directly. Conversely, your UI service can't know about objects
like Icon in the client so it can't talk to them.
This is exactly the sort of thing that needs to be explained and justified rather than simply stated. Even if the client knows about objects in my subsystem, it does not mean that it knows the implementations of those objects. There can still be limitless layers of complexity that are hidden from the client beneath those exposed objects. In fact, those exposed objects could be nothing more than place-holders to satisfy what the client expects from the subsystem interface while having no role at all in the implementation of the subsystem.
At the scale of a subsystem, the implementation that is being hidden /are/ the objects. The objects in the subsystem are abstracted from the problem space and tailored specifically to the subsystem's subject matter. That abstraction and tailoring is nobody's business except the subsystem's.
The GoF Facade pattern is designed to reduce complexity for the client. If the complexity is actually increased by trying to pack everything into a unified facade object then doing so is not appropriate.
As I indicated above, for large subsystem one can provide multiple Facade objects. In fact, that is fairly common when a subsystem needs to talk to multiple other subsystems. But those Facade objects provide the interface rather than the subsystem implementation. They still hide the subsystem objects, regardless of how one subdivides the interface.
Here is a quote from Design Patterns, Implementation of Facade section:
"A subsystem is analogous to a class in that both have interfaces, and both encapsulate something--a class encapsulates state and operations, while a subsystem encapsulates classes. And just as it's useful to think of the public and private interface of a class, we can think of the public and private interface of a subsystem.
Exactly. The Facade provides the /subsystem/ interface to the outside world, not the individual class interfaces. Note the last clause in the first sentence.
"The public interface to a subsystem consists of classes that all clients can accesss; the private interface is just for subsystem extenders. The Facade class is part of the public interface, of course, but it's not the only part. Other subsystem classes are usually public as well."
Here the GoF and anyone who has worked on full automatic code generators part company. B-) If you are going to encapsulate a subsystem, you need to encapsulate the whole thing. It becomes a nightmare to provide things like OTS harnesses for test automation in the IDE if the subsystem is only partially encapsulated.
In addition, from a Systems Engineering viewpoint, subsystems should be black boxes and the only way ensure that perspective is to fully encapsulate them. Similarly, if one is to have any hope of large-scale or component level reuse, the modules and components must be fully encapsulated.
Also, in a subsystem or component context, that view just doesn't jibe with general OO methodology. One can think of a subsystem as an object on steroids. The subject matter is an identifiable problem space entity (albeit almost always conceptual). As such the subject matter _as a whole_ has an interface represented by the Facade. The interface identifies the public responsibilities _of the subsystem_. How those responsibilities are implemented is nobody else's business.
But if one incorporates the interfaces of the objects that implement the subsystem as part of the Facade, one is blurring the boundary between responsibility and implementation. That's because the object is already an abstraction one needed to implement the subject matter itself.
Finally, as a practical matter one wants to use the subsystem interface to raise the level of abstraction for access to the subsystem services. Ideally one wants a subsystem interface that will work for any client needing those services. To provide that sort of client-independent interface one needs to capture the invariants of the subject matter in the interface. Including a subsystem object's interface in the subsystem Facade pretty much trashes that possibility.
On the utility of handles:
[...]
To clarify, my problem is not with handles per se. As I mentioned,
one really can't implement decoupling interfaces in asynchronous environments without them. My problem is with using them in this context. I suspect the client already has a reasonable way to
identify Icons. Rather than having the client keep track of how
your Symbol addresses map to Icon identity, I think it would be
better for the client to just provide you with Icon identity and
let you map that to Symbol identity internally.
I think I can see why you would think that, but I have concerns. Your suspicion that the client already has an identifier for symbols is not always correct. In fact, in the practical implementation that I am working on, often the client uses a factory to create a symbol constructively out of several parts and then takes the resulting Symbol as its only identifier for the new symbol. If the UI subsystem did not provide the identifier the client would be forced to create a new arbitrary identifier in that case.
First, I hope you meant to say 'icon' (the term you used previously to describe the client) here rather than 'symbol'. B-) We are having enough disconnects without confusing the semantics of rendering with the client's view of the world.
If the client can cobble together new things by combining existing components, then the client is going to have some concept of what that new thing is (e.g., Scenic Landscape) that is different that the client's notion of what the components are (e.g., Pine Tree and Cow). The client is also going to know about the Whole/Part relationship. So there is identity and there are relationships somewhere in the client's domain.
It then becomes a matter of conveying that identity and those relationships to the UI subsystem so that it can perform a corresponding cobbling together of its Symbols. In principle the identity of Scenic Landscape is no different than the identity of Cow once an interface mechanism for defining the relationships between identifiers is provided.
Plus, the client is not actually forced to keep track of what each Symbol object represents. It is not impossible for it to request that the factory create a new copy of a Symbol that it has already created. So the client does not need keep a table mapping 'A' to one Symbol and 'B' to another and 'C' to another, it can just order the creation of those Symbols each time it needs them.
Letting the client keep track of the Symbols that it needs also allows the client to discard Symbols that it no longer needs, while the subsystem would have to maintain a list of every symbol ever created. (Or else it would need a dispose(symbolID) method, which works but requires special garbage collection effort from the client.)
These two paragraphs seem in conflict for the situation where conversions between multiple Symbols are needed. I was nodding my head, Yeah, yeah, yeah when I read the first paragraph (up to the last clause). But the last clause and the second paragraph only makes sense to me if one is talking about icons in the client domain rather than symbols in the UI implementation. Otherwise there is ambiguity about which Symbol one is talking about ("natural" or "terminal-ready").
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
.
- Follow-Ups:
- Re: Text terminal rendering design
- From: Brendan Guild
- Re: Text terminal rendering design
- References:
- Text terminal rendering design
- From: Brendan Guild
- Re: Text terminal rendering design
- From: H. S. Lahman
- Re: Text terminal rendering design
- From: Brendan Guild
- Re: Text terminal rendering design
- From: H. S. Lahman
- Re: Text terminal rendering design
- From: Brendan Guild
- Re: Text terminal rendering design
- From: H. S. Lahman
- Re: Text terminal rendering design
- From: Brendan Guild
- Re: Text terminal rendering design
- From: H. S. Lahman
- Re: Text terminal rendering design
- From: Brendan Guild
- Re: Text terminal rendering design
- From: H. S. Lahman
- Re: Text terminal rendering design
- From: Brendan Guild
- Text terminal rendering design
- Prev by Date: Re: Is OO anti-Math? (Re: Whose Fish?)
- Next by Date: Re: A starting point into the world of OO
- Previous by thread: Re: Text terminal rendering design
- Next by thread: Re: Text terminal rendering design
- Index(es):