[logo]

JX Application Framework

Home

Introduction

Tutorial
    Class tree

    Open protocols

GitHub

Features
    Object messaging

    Extensibility

    Drag-and-Drop

    Networking

    3D Graphics

    Powerful tables

    Styled text editor

    Memory leak debugger

FAQ

Other software

Model-View-Controller

Code is easier to understand and maintain when it is written as loosely coupled, reusable modules. Model-View-Controller provides a paradigm for achieving this which works very well when combined with the OOP. The basic idea is to decouple your code into three parts:

  1. Model -- This stores the data.

  2. View -- This displays the data in a particular way.

  3. Controller -- This lets the user interact with and modify the data.

The best example in JX is the Table suite. A derived class of JTableData stores the data, JTable draws the data, and a derived class decides what to do in response to mouse clicks.

By separating the Model from the rest, one can make it system independent and therefore reusable in other programs. In practice, the View and the Controller often end up tightly coupled because a particular view is often designed to allow a particular kind of interaction.

One only achieves true separation between the Model and the rest by using messages rather than function calls. In JCore, this is handled by JBroadcaster. The messages are broadcast from the Model to all objects that are listening, not just to a particular object. Thus, when the Model sends "this piece of me changed," the View receives it and redraws itself.

Messages also solve the problem of displaying multiple Views of a single Model. With direct function calls, the Model has to know about every View. With messages, all the Views just listen to the Model via JBroadcaster.

The mechanics of JBroadcaster

Sending messages in JCore is very simple. Both the sender and receiver must inherit virtually from JBroadcaster. To begin receiving messages, the receiver uses the following code in one of its member functions:
    JBroadcaster* sender;
    ListenTo(sender);
When the sender broadcasts a message, the receiver's Receive() function is called. This function is declared and used as follows:
class MyReceiver : virtual public JBroadcaster
{
protected:

    virtual void Receive(JBroadcaster* sender, const Message& message);

private:

    MySender* itsSender;   // it's your problem to get a pointer to it
};

void
MyReceiver::Receive
    (
    JBroadcaster*  sender,
    const Message& message
    )
{
    if (sender == itsSender &&
        message.Is(MySender::kMyMessage))
        {
        // do something
        }

    // You should pass it to your base class
    // if you don't want the message yourself
    // or if there is any chance that the base
    // class is also listening.
}
Messages are themselves objects, and can therefore contain both data and functions for the receiver to use. In this trivial example, here is how MyMessage would be declared:
class MySender : virtual public JBroadcaster
{
public:

    static const JCharacter* kMyMessage;

    class MyMessage : public JBroadcaster::Message
        {
        public:

            MyMessage()
                :
                JBroadcaster::Message(kMyMessage)
                { };
        };
}

const JCharacter* MySender::kMyMessage = "MySender::MyMessage";

Additional functionality

BroadcastWithFeedback() triggers ReceiveWithFeedback() instead of Receive(). ReceiveWithFeedback() takes a non-const Message* so that it can be modified. This allows the recipient to change the message and provide feedback to the sender.

Send() and SendWithFeedback() allow messages to be sent to a single object in a way that is safe but that does not require the C++ type safety mechanism of dynamic_cast. Essentially, this feature is equivalent to the object methods provided by Objective C.

ReceiveGoingAway() is called when the object to which one is listening has been deleted. (It is not necessary to call StopListening() because the connection is terminated automatically.)

Comparison to other messaging systems