Re: Text terminal rendering design



Responding to Guild...

Generally when requirements change one has to modify
implementations more often than interfaces, as you imply above.
That's why we hide implementations behind interfaces. But that
applies to entire subsystem just as much as it applies to
individual objects.


You write as if you don't expect me to agree with you, but of course I do agree. The disconnect here seems to be rather strange.

If you agreed with me you would not use SymbolFactory and Terminal as
interfaces. B-) They are elements of a unique design vision for the UI
subsystem subject matter so we need an interface to encapsulate them.

I know that you are aware that revealing an object reveals nothing more than the public members of that object. The public members are the interface of that object and taken together all the interfaces of all the revealed objects becomes the interface of the subsystem.

The only way you can reveal an object without defining its properties is
as a handle or referential attribute. Your client is invoking specific
responsibilities of the objects. To do that there must be a full class
definition, even if it is an abstract base class in a generalization.
That class definition defines every public responsibilities that every
object member in every descendant subclass share.

The key point here is that the interface to the subsystem is not the
same as the public interface of the objects that implement the
subsystem. There is only one subsystem interface that is part of a
bridge to the client. One client = one interface. Write on the
blackboard 100 times:

The job of Facade is to hide the interfaces of the objects that
implement the subsystem subject matter.

I wonder if the disconnect comes from you thinking that I am revealing an object that has public members that the client should not see. I assure you that I am not. The objects that I reveal to the client have only public members that correspond directly with messages that I expect the client to send to the subsystem (or else they are for giving the client access to other interface objects).

I assure you that you are. Your client directly invokes responsibilities of the Terminal and SymbolFactory objects. To do that the class
definition must be exposed to the client implementation.

You are thinking at the 3GL level like a type maven. The class definition identifies /responsibilities/. It is only in 3GL type systems that the method /signature/ is a message, and then only for synchronous method calls. The mapping to messages at the 3GL level is just an artifact of procedural message passing. But the class definition /always/ defines responsibilities throughout OOA/D/P.

There is a huge difference between displayIcon() and createSymbol(). The
createSymbol() behavior is only one activity of potentially several that
are necessary to service the displayIcon() request _within the UI
subject matter_. Each of those activities are specific to the
implementation of the UI subject matter.

But surely there is always a 1:1 mapping between subsystem
interface messages and object method calls. How else can the
client send the subsystem messages but through method calls?

No way, Jose. For example, in the electronics test industry
individual test instruments usually provide interfaces for three
different low-level activities: Setup [the instrument]; Initiate
[the test]; and Fetch [the results.]


[snipped interesting example]

The point of your example seems to be that one message to the subsystem can lead to several method invocations internally. However, that does not address the intent of my question. I was not talking about how a subsystem deals with messages internally, I was talking simply about how the client sends messages to the subsystem. This must surely happen by the client invoking interface methods.

Yes, that was my point: that the mapping between subsystem interface
messages and object method calls is not necessarily 1:1 and quite often
isn't.

There are other ways to send messages than synchronous method calls. One sends messages to/from hardware by setting bits in registers. In an
event-based system the client just pushes an event onto the subsystem
queue. That usually involves invoking a method of an Event Queue object,
but conceivably it could be done through shared memory.

Specific to your question, though, the message passing mechanism doesn't
matter. The 3GLs all use procedural message passing. One reason we want
a Facade that hides object interfaces is because the client's single
method call may require multiple methods calls within the subsystem. More relevant to the overall issue here is that the single client method call can kick off a daisy chain of method calls for multiple collaborations among several objects within the subsystem implementation.

That would be the case for my displayIcon message. It would kick off a
sequence of object collaborations, each triggered by a method call to an
object implementing the subsystem. But after the initial dispatch from the Facade interface, those calls would be daisy-chained /within/ the subsystem implementation.

How the subsystem reacts to those method calls is an entirely separate and unrelated issue. I hope you notice that just as a facade object is free to call whatever methods and however many methods that it chooses to relay the message to the subsystem, so can any object, even an implementation objects.

But that is exactly the point. The client calls a method in the
subsystem Facade. That hides the implementation of the subsystem from
the client, including an arbitrary number of internal collaborations
that are needed to respond to the message.

More to the point, an implementation object could be transformed into a facade during maintenance with no effect on the client, just as a facade could be transformed into an implementation object with no effect on the client. You have mentioned that facade objects might tend to become more complicated during maintenance as the design of the subsystem changes. If the facade becomes complicated enough, it might end up with serious implementation responsibilities.

The point is that you NEVER, EVER want to make the interface of an
object that implements the subsystem be part of the subsystem interface.
Doing so immediately exposes the implementation of the subsystem to the
client. Write on the blackboard 100 times:

The job of Facade is to hide the interfaces of the objects that
implement the subsystem subject matter.

If you don't like that, you can always revert back to an earlier design. Is this not true? If it is true, then surely it is the very definition of decoupling! The fact that I can make the radical alteration of turning a facade object into an implementation object or an implementation object into a facade object without the slightest change to the client proves that they are decoupled.

It is not whether one can swap back and forth, it is about whether one
should. The OO paradigm says one should always hide the implementation so one shouldn't.

Abstraction is also important. The subsystem interface should
capture the invariants of the subsystem's subject matter from the
client's perspective. In almost all client/service relationships
the client will be at a higher level of abstraction than the
service. That quite commonly requires the decomposition of client
requests.


Method invocations are naturally handled by taking a request from some caller and turning it into a series of steps that the object performs. Facade objects are not the only objects capable of decomposing a request.

No, but they are the only way to decouple the client from the
decomposition itself.

This is why I was pushing on the fact that your client wants to
think about displayIcon rather than createSymbolTypeX. In fact,
the call to SymbolFactory is just one of several calls that may be
necessary to service the client's request. That sequence --
including where it starts -- is a private matter for the UI
subsystem implementation.


Then it is my subsystem interface that needs to be adjusted. The fact that I give the client implementation objects to receive the client's messages is an entirely separate issue. If I am going to change the interface then naturally I will have to change the object that handles those messages. Depending on the interface that I finally settle upon, it might be a facade object.

Yes, you need to change the interface to the subsystem. If you do that
properly, the Facade will never be an implementation object. Write on
the blackboard 100 times:

The job of Facade is to hide the interfaces of the objects that
implement the subsystem subject matter.

IOW, the main reason you currently need to change the subsystem
interface is so that it won't expose implementation objects.

The indirection that one needs in hiding the subsystem's
implementation is that the client can't know what objects
implement that subsystem.


You are saying that in a misleading way. Based on what you wrote below, this isn't really about what the client knows or doesn't know. I think we agree that the client can never know what objects implement the subsystem, even if the client is given a pointer to each and every one of those objects.

If we agreed on that your interface would not expose Terminal and
SymbolFactory. B-)

This ignorance comes directly from the fact that the client has no way of knowing if the objects it sees are implementation objects or facade objects. Since you agree with that, perhaps it would be better to explain your position in another way.

But the coupling exists even if the client thinks they are Facade
objects. That coupling is a problem when the implementation objects
change and break the client. A properly designed Facade should be vastly
more stable that the interfaces of implementation objects.

As soon as the client knows that SymbolFactory is an object in the
subject matter, the client knows something about that
implementation.


That's true, but a little bizarre. What makes you think that the client would know that SymbolFactory is an object in the subject matter? Are you going to tell him yourself? I'm not going to tell him.

Don't get hung up on "knows". A more accurate notion would be what is
visible to the client. The literature of dependency management tends to
use the "knows" idiom, probably because the particular responsibilities
and interface are available for use. Thus if the client knows about them
the client can use them and if the client is already using them and they
change, it breaks what the client knows about them.

The coupling problems arise from the service side when changes to the
implementation of the service require that the client's implementation
be modified.

For example, suppose requirements change and you decide that
instead of using the Abstract Factory pattern, you need to use the
Factory Method pattern for creating symbols. To document the
implementation so it is clear what pattern is being used, you
might choose to rename SymbolFactory to SymbolCreator.


If I want the client to tell the subsystem what symbols to create, then what you are describing is a subsystem interface change.

And the point is that with good subject matter definition and a good,
high-level, client-oriented Facade interface there would be no need to
tell the UI subsystem to create a symbol. The client just wants to
displayIcon. It doesn't know or care that creating symbols is necessary
to that.

Now that is clearly a private matter for the implementation of the
UI subsystem.


That is not clear at all. This subsystem is designed to serve the client's needs in displaying symbols to the user, therefore the client is the ultimate source for all symbols.

The client is the source of icons to be displayed. The notion of
terminal-ready symbols exists only in the context of a specific design
vision for a UI subject matter. How the client's icons map into symbols
is a private matter for the UI subsystem.


The subsystem doesn't tend to create symbols for itself. By nature only the client knows what symbols should be displayed and SymbolFactory is an attempt to use Abstract Factory to allow the client to abstractly convey that information to the subsystem.

If SymbolFactory should change, then it can only be because we have found a new and better way for the client to inform the subsystem about what symbols need to be displayed. If SymbolFactory changes but the subsystem interface does not, then what is the point?

Do you honestly not see a major difference in level of abstraction between

UI.displayIcon

vs.

SymbolFactory.createSymbol?

Creating a symbol is only one activity the UI subsystem needs to perform
to render the client's icon in the display. Why should the client need
to know about that activity in the grand scheme of displaying an icon?
Moreover, it is nearly at the end of the chain of those activities,
especially when a symbol conversion is required. Why should that chain
be visible to the client who wants to display one of its icons?

If you have a separate Facade interface, that renaming will be
completely transparent to the client.


Despite my doubts about your example, I should point out that even if I assume there is a good reason for changing SymbolFactory into SymbolCreator and hiding it from the client, your example still does not make its point because I can make the renaming transparent to the client without having a separate Facade interface.

Of course, I have to keep SymbolFactory around since it is a part of the subsystem interface, but I am completely free to create a class called SymbolCreator and use it internally in place of SymbolFactory. If I still think the client's instructions to create symbols are worth something, I can even relay those message to SymbolCreator through SymbolFactory.

Yes, you could do that. In fact, that is the only way to make an
implementation object into a Facade: remove all of its subject matter
functionality and delegate that functionality to another object in the implementation. Then it really is a Facade because it is now hiding the interface of the object that is actually implementing the behaviors.

Why would it need to know that icons were displayed on terminals
or that terminals needed to be initialized?

That depends on what you take the word 'terminal' to be. I take
it to be nothing more than an array of symbols. The client needs
to know that because I cannot think of any way more abstract than
that to describe it. If the client didn't even know the symbols
were being displayed in an array, how could it provide
coordinates?

If that is all it is, then why does it have behaviors like init()
and shutdown()? B-)


That's a good point. I was overstating the abstraction that I am using. Still, init() and shutdown() are really pretty abstract. Even if I were implementing this as a smoke signals I would want messages like that, especially shutdown(). I would need the client to tell me when it is safe to put the fire out.

But for smoke signals would you really choose Terminal as a problem
space abstraction?

I took it to be an abstraction of the particular hardware display mechanism with unique properties that affected how symbols would
be processed. IOW, it would be the Terminal object that described
the differences between 25x80 character display and a 1600x1200
pixel display.


That seems about right, though I imagine the number of pixels in the display would be encapsulated within the object and not open to examination. On the other hand, I plan to have the width and height of the display in characters be available to the subsystem client upon request. It needs that to know what coordinates will be visible to the user.

All you need for that is some notion of display in two dimensions. You
can express that quite abstractly in the subsystem interface without
getting into notions like terminals.

You already have an abstract notion of an array of symbols in
2DArray. [Whose name captures that idea a whole lot better. B-)]


I have my doubts about that name, though. 2DArray suggests a 2D array of something, not necessarily symbols. And the abstraction is naturally not exactly as I said it above, since it is also part of the abstraction that those symbols are to be displayed to the user. That part is certainly not captured by the name 2DArray.

I agree that I spoke too quickly. The original 2DArray was just a lookup
table based on icon identifier. However, the notion of a matrix indexed
by {x,y} with symbol info in the cells still seems useful.

[BTW, it occurs to me that the differences in terminals are
probably easily parameterized. So one probably only needs a single
flavor of Terminal with appropriate attributes whose values define
differences.]


That is highly doubtful. Perhaps some terminals can be handled that way, but the differences between a graphical terminal and a PDCurses terminal are far more radical.

PDCurses is an implementation tool for text terminals. Solve the more
general customer problem and then worry about whether you can save some
keystrokes using it.

I suppose that it doesn't really need to know that terminals need
to be initialized, but as it happens they do. The initialization
message is mostly just a courtesy to the subsystem to help it
provide an efficient implementation by not having to guess too
much about what the client will do.

Part of the DbC contract with the UI subsystem may well be some
sort of mapping for when startup and shutdown activities occur
that is driven by the practical requirements around display
mechanisms. But my point here is that the client doesn't need to
know the details.


What details are you supposing I am asking the client to know about? It is an init() method, just like that. It takes no arguments and it is nothing but an announcement that the client is about to need to display some symbols. What did I say to suggest otherwise?

The client should see init() as a subsystem responsibility, not a
Terminal or Fireplace responsibility. I just want to avoid the client invoking Terminal.init().

There just needs to be something in the client space that
naturally maps into triggering those activities. I am guessing the
the client knows when it needs to use the display and when it is
done.


You have guessed correctly. The sole purpose of the init() method is allowing the client to announce one of those things. It is strange that we agree on so much and yet you write as if we did not.

OK, but that just amplifies the point above. The client wants to start
displaying things or stop displaying things. The client does not want to
initialize Terminals or shutdown Terminals.

Why would it make any difference to the client if the icons were
displayed on a computer or with Navajo smoke signals?

I rather think that it wouldn't make any difference at all. In
fact, that is the point of all this abstraction that I am
introducing and the object-oriented design. If I wanted the
client to be forced to use one particular implementation I would
just have it use PDCurses.

Yes, but then there is no Terminal object. Instead we have to make
due with Fireplace and Blanket abstractions.


You are the one suggesting thie unusual implementation. Can you blame me for choosing slightly inappropriate names for objects when they are going to be implemented in radically unexpected ways? It may be the case that Terminal is a strange name for an object that organizes smoke signals, but that does not mean that it cannot do it.

I am sure that the appropriate subclass of Terminal would gladly make use of Fireplace and Blanket to send out smoke signals, although the concept of coordinates might be a little awkward. Terminal encapsulates anything that anyone might use to figure out whether it is smoke signals or a machine doing the displaying.

The point is that when you implement the subject matter you must
abstract its problem space accurately. There are no terminals among the
problem space entities involved with sending smoke signals.

My issue here is that the interface should be abstract enough that
the client doesn't care how icons are displayed.


If you think that it is not abstract enough as it is, then please suggest ways in which I could make it more abstract. You don't need to tell me that an abstract interface is a good thing; it is currently as abstract as I can manage.

Use a single displayIcon message rather than separate messages to
Terminal, SymbolFactory, and whoever selects the SymbolFactory and
creates a source Symbol for conversions. Daisy chain all the rest of the
collaborations within the subsystem until the icon is rendered.

My problem is that you seem to think that the object that implements the interface determines how abstract the interface is, while actually the abstractness of the interface depends only upon the interface itself.

The abstractness of the interfaces of implementation objects are exactly
at the level of abstraction defined for the subject matter and it is
focused on the subject matter. The subsystem interface is usually at a
higher level of abstraction and is focused on the client.

Think of the subsystem Facade wrapper as a polymorphic dispatch mechanism that allows one to swap display paradigms (e.g., DLLs
for entirely different subsystems) without the client knowing
anything about it.


You are talking as if my current design does not already allow that. That was the fundamental goal of this project from the very beginning. I don't know why you seem to think my current design fails to allow that sort of swap, but I am seriously attempting to discover it.

It doesn't support smoke signals, holograms, or heliographs. Those
things need to be abstracted differently because they are fundamentally
different than computer terminals. So much so that swapping subsystems
would probably be much easier than trying to make a single
one-size-fits-all subsystem.

In my career I have watched four major display paradigms dominate the
industry in different decades. Every time the paradigm shifted there was a great gnashing of teeth because great gobs of legacy code were married to particular paradigms in the same way you want the client to be married to notions like Terminal and SymbolFactory. Those problems could have been avoided if the software talked to a single, abstract interface that captured display invariants. Then they could have swapped out the entire subsystem implementation without touching the client code, which would continue to use the same interface.

It is unlikely we will have another major paradigm shift for displays in
the couple of months, but the cost of being ready for it is infinitesimal compared to the aggravation of not being prepared for if it does happen.

It's because SymbolFactory and Terminal are specific to a
particular design solution for the UI subsystem. The notion of
Symbol itself is a specific abstraction that fits into a
particular vision of the solution. However natural all that stuff
might seem to you as the UI subsystem designer, it isn't the only
way to solve the problem.


That stuff seemed natural to me when I put myself in the place of the client. You are talking about my vision of the client's subsystem interface, not the internal subsystem design. I get the impression that my subsystem interface seems incredibly foolish and restrictive to you and that is why I am so eager to find a better one.

Not foolish. Very smart people built subsystems with that sort of
coupling and bleeding cohesion for decades. I spent twenty years doing
it well into the '70s because only the R-T/E people had figured out
modularity and APIs and I wasn't doing R-T/E then. And there really
wasn't a cookbook methodology for it until OOA/D matured in he late '80s.

I am arguing that it is not natural from the client's perspective. The
client just wants to display a bunch of icons in a 2D display. That's
WHAT the client wants to do. Where is there anything in that that
suggests terminals, conversions, terminal-ready symbols, and all the
rest? That stuff only exists if you try to figure out HOW an icon is
displayed on a computer terminal.

The client should be telling the UI What to do, not How to do it. So the
subsystem interface should describe What the subsystem can do, not How it
actually does it.

So you need a subsystem interface that is independent a particular
design vision. For that you need an interface that is at a higher
level of abstraction consistent with the client's view of the
world rather than the UI's.


So, if you were the client programmer, knowing what you know about the purpose of this subsystem, what interface would you suggest? I mean including colors and symbols that can be drawn using arbitrary client drawing procedures. It would also be nice to support ASCII, Unicode, various font attributes such as bold and underline, and also line-drawing symbols such as horizontal lines and vertical lines and diagonal slashes and corners.

So far all I see are four interface methods in a single Facade object:

initDisplay()
displayTextIcon (characterCode, x, y, isASCII, color, font, ...)
displayGraphicIcon (iconID, x, y, format, dataHandle)
shutdownDisplay()

Note that these are Facade methods that define what the subsystem's responsibilities are. I would expect the messages that client implementation sends to its output interface would be more like:

readyToDisplay
textIconReadyForDisplay
graphicIconReadyForDisplay
displayCompleted

That is the client's view of what is happening. It is an
announcement of the client's state.


Agreed.


The client should not have any expectations about what will
happen, if anything, in response to that announcement.


Why would it?

That's the problem with invoking SymbolFactory.createSymbol -- there is an expectation that a Symbol will be created at that point in the overall display processing.

Mapping that into an internal responsibility to initialize some
hardware is the UI subsystem's problem, not the client's.


That is exactly what my current design is doing.

No, it isn't. SymbolFactory.createSymbol () defines a fundamental behavior responsibility. It can only be invoked if one has an object that is a member of the [SymbolFactory] class in hand. Polymorphic dispatch does nothing to hide that.

It is completely unexpected how you suddenly assume that just
because a few implementation objects are exposed that the entire implementation is suddenly exposed to the client, and worse, that
the client is forced to deal with it. On the contrary, none of
the implementation is exposed to the client.

Those objects /are/ the implementation.
>
Not exactly. Those objects encapsulate the implementation. There is a big difference. In one case the client has a hold of the implementation, and in the other the client only has a hold of objects that are deliberately hiding the implementation.

That is the wrong level of indirection. Write on the blackboard 100 times:

The job of Facade is to hide the interfaces of the objects that
implement the subsystem subject matter.

It seems to me that those conversion procedures depend solely on
the particular flavor of terminal in hand, which the UI subsystem
is supposed to be making transparent to the client.


The UI subsystem is certainly supposed to be making that transparent, I completely agree with that. However, the conversion procedures are not at all solely dependent upon the particular flavor of terminal. (If they were, things would be much easier.)

Perhaps not, but the fact that a conversion process is necessary at all is a private matter of the UI subject matter implementation. That is what I want to hide.

If the UI knows what flavor of terminal is active and it knows what
it needs to display, it /must/ know how to convert it.


The conversion procedure could also be called a decoding procedure. The client has some sort of encoded symbol representation and the subsystem needs to figure out what it means before it can know what it needs to display. Unfortunately, by their very nature, there is no universal standard way to express a symbol, so all representation schemes can be viewed as being in some sort of special code.

That decoding has to be in the UI subsystem. The client wants to display an icon. To do that it has to send the UI subsystem information about the icon. That information is encoded in a message data packet. The UI subsystem always needs to know how to decode that message data packet from the perspective of the UI subject matter.

That's why we use pure message interfaces. The message data packet can be encoded/decoded on each side with quite different semantics. It is the same sort of perspective shift one has if the client sends "I'm done with displaying icons" and the UI interprets that as "Time to shutdown the terminal".

I could demand that the client conform to one particular encoding and make the conversion process trivial, but that is impractical because it would require a almost universal encoding scheme, which I think we agree does not exist.

Consider true graphic icons. There are multiple standards for representation in the problem space (BMP, GIF, JPG, et al). If you want to be reusable you can support all of them. But the client will have to tell your which one it is providing, which will be part of the general DbC contract.

The client can even use a proprietary format internally, but then it would have to convert to a standard format or provide a description in the data packet that is format-independent (e.g., CDIFF).

Note that standards like JPG represent one form of invariants of display. Any graphic can be represented unambiguously with the standard's semantic meta-model. Supporting a standard like that is exactly what the subsystem interface needs to abstract display processing.

<Hot Button>
Alas, the industry can't settle on a single standard. (Perhaps somewhat more accurately, the industry keeps coming up with better ones.) There is a heavy cost to the consumer hidden in that precisely because of the redundant developer effort in supporting multiple standards that is passed on in the product price.

The computer hardware industry has had seven decades to provide a standard for things like endian and lsb location. But they have chosen to deliberately use proprietary standards to make interoperability difficult so that customers would be forced to use one vendor. The software industry got fed up and decided to use ASCII interfaces like HTML and state transfer mechanisms like XML to provide interoperability.

The result is that because of that software end run the hardware companies failed in their goal and most customers have hybrid hardware systems. However, the customers are now stuck with ASCII encode/decode, which is terribly inefficient. Worse, the software industry has proceeded to provide a gazillion interchange and markup standards so we also have the cost of redundant development to support them all.

But there is an even more subtle price being paid. Back in the '50s and '60s markup and scripting languages were very popular. But by the mid-'70s they were largely abandoned. (One author stated in a refereed journal that the first markup language was developed in 1986!) There was a reason for that: they are very difficult to maintain. Modern WYSIWYG tools and automation have alleviated a lot of that, but every time you encounter a web site form that is broken, the odds are very good there is a CGI or Javascript behind it that isn't quite right. Another manifestation is the dozen or more developers dedicated to supporting a POS web site that is basic just CRUD/USER processing that would have required one half-time developer if it was a traditional GUI.
</Hot Button>

Whatever encoding I ask the client to use for inputting the symbols might be perfect for a certain implementation, such as ASCII for a PDCurses terminal, but it could be terrible for another, such as smoke signals.

That's why you have the UI subsystem. B-) It's mission in life to convert the client's view to the terminal's view.

I really had no idea that you would suppose I would give such a header file to the client. I'm talking about encapsulation and
how I haven't really exposed anything and you are thinking that
I've pulled down the pants of all my classes like this.

Then I am confused. You said that the client directly invokes
methods of Terminal and SymbolFactory because they are part of the
subsystem Facade. I don't know what language your are using, but
to compile the caller the compiler needs to understand the class
structure.


That is true if by "class structure" you mean the set of messages that the objects of the class accept. Of course, the client is always forced to understand a set of messages no matter what subsystem it is using.

I did not mean to suggest that I wasn't giving any header file at all to the client. I only though it funny that you would suggest I give a header file that shows my class's private members to the client. I may not be as experienced at object-oriented design as you are, but even I could spot that sort of hole in my encapsulation.

There is nothing to prevent the superclass header file from identifying private properties that are shared by all members. If the superclass defines knowledge attributes that are shared and one of them is changed, you will have to recompile.

But the real problem lies in exposing the objects and responsibilities that implement the subject matter. That superclass definition identifies every object of every descendant subclass and all of the responsibilities that they share. All you are hiding by using the superclass definition are the differences in implementations of those responsibilities.

The header file contains a class definition, of course, but it
has no private members. In fact, it doesn't really have any
public members, at least not directly. The members are denoted as
being pure virtual, which means to C++ folk that they are not
implemented here.

[...]

All you are doing here is using polymorphic dispatch through an
abstract base superclass.


That is a technically correct description of what I am doing, but it neglects the spirit of what I am doing. The header file could be seen as an abstract class declaration by a compiler, but a human looking at it sees a declaration of the messages that my subsystem will accept. Surely you would have such a thing in the subsystems that you design and it would look much the same.

Alas, the header isn't that vague. It is a set definition. It defines a set of objects in terms of the responsibilities that they all must have. Those objects and responsibilities have been abstracted from the subject matter problem space specifically to solve the subsystem's problem. They are the subsystem implementation.

In contrast, the Facade header defines one object with very restricted mission and responsibilities -- to decouple the client from the objects, interfaces, relationships, and responsibilities that implement the subject matter. The subject matter that the Facade object implements is that of inter-subsystem communications, not the subsystem subject matter.

That allows you to substitute implementations of the subclasses.


That is the swapping that you seemed to be suggesting I could not do earlier in the post.

The swapping that you can't do is subject matters, like terminal display versus holograms.

But it doesn't allow you to change the names,


I can change the name of the class, of course. Each subclass necessarily has its own name and I can change that freely to almost anything I like.

You can't substitute a Fireplace superclass for a Terminal superclass.

I cannot change the names of the methods without breaking the subsystem interface, but why would I want to do that? I'm not giving the client this object lightly; I am giving the client this object because these methods are the methods that the client would want to invoke to interact with my subsystem. If I change the names of the methods, that would confuse the client. (Unless I change the names to something better, which I would be glad to do given any suggestions.)

During maintenance objects come and go or have new new or modified semantics. You have two obligations during maintenance: to correctly implement the requirements change and make the code maintainable. That can trigger name changes.

This is especially true during OOP. Dependency management refactoring will quite commonly trigger the introduction of "buffer" classes and new superclasses that sit between the original message sender and the receiver. Pick up a book like Fowler's "Refactoring" to see just how pervasive this sort of thing is when trying to deal with physical coupling in the OOPLs.

As for the rest of the paragraph, I won't repeat the arguments I made above and elsewhere that the client doesn't want to know anything about those methods.

If I am also calling those methods internally and I don't like the look of the names, then I can change the names internally by either relaying the client's messages to an equivalent object with different method names, or by relaying my internal calls through an object with different method names to this object. However, that seems unlikely, since the method names should have been chosen with good reason and it is unusual for the subsystem to be calling the methods that are intended for the client, since the subsystem is rarely in a position to pretend to be the client.

If you hide that implementation, you don't need to worry about the client at all when you change the names. You just dispatch to the new method name in the Facade implementation. IOW, the mapping is always in the Facade interface, not down among the various implementation classes.

invoke different methods,


I am not invoking methods; the client is invoking methods. That is unless you mean the methods that get invoked in response to the client's messages. In that case I am free to invoke whatever I want.

That is exactly the problem -- the client is directly invoking methods of implementation objects. If you do something like remove that method and replace it with two new methods, then the client is broken even though the service the subject matter provide is the same.


dispatch to members of different classes,


If I want to dispatch to another object then this object can act as a facade and relay the message. Surely you are not arguing against facades.

No, but implementation objects are not Facades. (Actually, one can have Facades within a complex subsystem, but those are not exposed to subsystem clients.) Write on the blackboard 100 times:

The job of Facade is to hide the interfaces of the objects that
implement the subsystem subject matter.

change int arguments to doubles,


If the client supplies ints then I have ints. This is the sort of thing that I must decide when I am designing the interface. There is nothing I can do about it in maintenance, even if I were using a facade.

But you aren't defining the interface the client wants to see. You are defining the interface for your implementation objects. If the client wants to supply doubles but you need to use ints for performance, it would be the job of the Facade implementation to resolve that syntactic mismatch with a conversion before invoking the implementation object.

But when the client directly invokes the implementation object's interface, you are forcing the client to use the units that you want used in your subject matter implementation. When you change you mind about the units for performance reasons, you break the client. To avoid that you have to provide the Facade that you should have provided in the first place.

[In your application such conversion issues are extremely unlikely to matter. But I've worked with applications where the performance issues around 16-bit vs. 32-bit integers were critical. The point is that you do not a priori know what machinations you will need to resolve nonfunctional requirements until you get there. And you may not get there until maintenance for new requirements. But you do want to make sure that resolution is transparent to the client.]

What you have not changed is that the client now knows: (A) a SymbolFactory abstraction is part of the subsystem implementation;


But you said yourself that the client does not know that. You said it below because you knew that I would point that out.

I am not sure what you are referring to. The closest thing that I can guess is that I agree you could make SymbolFactory a true Facade. But to do so you would have to remove all subject matter functionality from the method so that it no longer creates Symbols.

The issue here is that [SymbolFactory] /is/ an implementation object and it /is/ visible to the client so the client does know about it and its responsibilities. Among other things that means the client can invoke /any/ behavior responsibility or modify /any/ knowledge attribute exposed in the <super>class definition. It can even delete the object. All without regard to side effects on the UI subject matter.

(B) the SymbolFactory has a particular set of properties useful
for the subsystem implementation;


It knows that it has a particular set of methods that are useful for sending messages to the subsystem. It doesn't know about any other properties.

Not when the object is an implementation object. Those methods in the class definition are not messages; they are behavior responsibilities that have been exposed to the client. They only become messages when the 3GL type system maps to procedural message passing.

Note that one way of looking at the Facade pattern is that it is a means to provide separation of message and method at the 3GL level. In that sense it is an artificial construct to get around the hardware computational models, just like an event queue gets around the inherently serial processing of 3GLs.

[As it happens, the Facades that provide subsystem interfaces are rarely even shown in UML models for OOA/D just as one rarely clutters the model with separate lollipop Interface symbols for classes. That's because they are fundamental to the OO paradigm and, like event queues for Statecharts, are an assumed part of the infrastructure. One only needs to identify them explicitly in the unusual situation where one wants to provide multiple interfaces for the same entity. Thus the translation full code generators always know there is a dedicated Facade object and they will create one if it is not explicitly specified.]

(C) the responsibility being accessed is the way the subsystem
/currently/ kicks off processing of the client's request;


Every client request is kicked off by sending the subsystem a message. The client is always going to know that. Remember that all the header file reveals is a list of messages that the client can send to the subsystem.

Yes, but the client isn't supposed to know what implementation object and what behavior of that object kicks off the processing _in the subject matter implementation_.

Alas, the last sentence is incorrect, as I've discussed above. The method in the header file defines a behavior responsibility. To see that, assume the object has an internal state machine and the methods represent the state actions. The header file is unchanged, but one needs an STT, STD, or Statechart to understand the mapping of messages to them.

(D) /all/ of the defined responsibilities of SymbolFactory are
accessible to the client.


I wouldn't reveal SymbolFactory to the client if I didn't think it needed to give me the messages that SymbolFactory accepts. That includes all of them.

We keep going around on this. The client should not be aware that Symbols are needed to display an icon, much less that a SymbolFactory is needed with any of its specific responsibilities. SymbolFactory is a pure design abstraction for a particular vision of the subject matter solution.

I have explained why the client should not be aware of implementation object as well as I can. Anything further I say would just be repeating myself. So this is the last message where I am going to talk about the subsystem interface.

You can argue that the client doesn't /know/ SymbolFactory is an implementation object; from its perspective it is just an
interface.


Indeed I would argue that, so I thank you for conceding the point and reducing the disconnect between us.

I'm afraid I'm not conceding anything here. I am saying that the argument doesn't change the fact that the coupling and implementation dependencies exist. That's because...

The counter to that argument is that it doesn't matter;


Just to be clear, when we say that it doesn't matter we are not saying that it is false. Even if it doesn't matter, the client still does not know that SymbolFactory is an implementation object. I hope we agree on that.

....the coupling exists from the UI side whenever the object /is/ an implementation object. The coupling will be painfully manifested to the client when we make a change to the implementation object that breaks the client.

In this case we do know with absolute certainty that SymbolFactory /is/ an implementation object because we have discussed its behaviors at length. The coupling and implementation dependency in the client then exists as soon as we expose [SymbolFactory] and its responsibilities to the client. So as long as we know it is an implementation object, we need to eliminate that coupling even if the client doesn't immediately know it is there.


--

*************
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




.