UML Diagrams - CMPUT301F12T01/classproject GitHub Wiki
UML Diagrams
Actors
The currently identified actors in the system are:
- Users: users of the system
- TaskCreator: a user that can create a task
- TaskFulfill: a user that chooses to fulfill a task
- Server: the back-end server that hosts globally shared tasks.
The Universe
These are the most basic use cases within our system:
Abstract data types
These abstract data types are used ubiquitously in the system. They are
passed around almost like the base types (int
, double
, Boolean
,
String
, etc.).
Overall system design
The following diagram give a taste of the three-level interaction between the Android UI classes (providing views and controllers) and the "storage" classes the provide local persistent storage and global publication. The main models are described in greater detail in the following section.
Business logic layer
WARNING: This layer is severely out-of-date. Tell Eddie to change it, once the new model passes its most important tests.
This comprises the "Model" of "Model-View-Controller". The top layers (e.g., Android GUI) will provide views and controller for the top level model. Note that the top level model itself is a view to underlying models.
Sequence: Creating a new task
The following is a sequence diagram demonstrating the use of Model-View-Controller combined with the Observer pattern.
Here, the TaskEditorActivity
is the controller, adding a Task to the
TaskManager
. The TaskManager
finds the proper TaskCollection
and
adds this Task to it. Since TaskCollection
s are observable, it
notifies all of its observers of this change. Its observers include UIs
and the persistent storage interfaces, which display, store, or upload
the change.
Observer pattern with message passing
WARNING: the following scheme was created by a frustrated Erlang programmer.
Our design consists of this massive Model-View-Controller architecture.
Classes that actually handle storage and uploading are Observers
,
hence view to the model. This makes adding Task
s and Report
s really
easy, but appending any more actions to this and things get complicated
rather quickly. The solution is to send Message
s which are tuples
consisting of
- the action; and
- the object affected by the action -- called the "payload"
in notifyObservers()
call, which will call the receiver's update()
method.
This is strongly inspired by the following idiomatic Erlang code
(though please use gen_server
, or gen_event
for these kind of
things!), which handles client-server interaction:
%% In the client...
rpc(Message) -> {self(), Message} ! task_manager.
add(Task) -> rpc({add, Task}).
remove(Task) -> rpc({remove, Task}).
modify(Task) -> rpc({modify, Task}).
%% In the server...
loop(Database) ->
receive
{_Sender, {Action, Payload}} when is_record(Payload, task) ->
handle_task_action(Database, Action, Payload)
end.
handle_task_action(OldDatabase, add, Task) ->
NewDatabase = database:add(OldDatabase, Task),
loop(NewDatabase);
handle_task_action(OldDatabase, remove, Task) ->
NewDatabase = database:remove(OldDatabase, Task),
loop(NewDatabase);
handle_task_action(OldDatabase, modify, Task) ->
Key = tasklib:get_key(Task),
NewDatabase = database:replace(OldDatabase, Key, Task),
loop(NewDatabase).
Here, the lines
receive
{_Sender, {Action, Payload}} when is_record(Payload, task) ->
% ...
end.
are analogous to
public update(Observable sender, Object message) {
if (((Message) message).getPayload() instanceof Task)
// ...
}
The Message
class adds this functionality to Java. Some people say to
never try implementing one programming language in another;
evidentially, those people have never programmed in Java.
See the "Sequence: Creating a new task" to see the message passing in action!