2. The Data: what objects are and what objects do

The fundamental problem solved by DCI is that people have two different models in their heads of a single, unified thing called an object. They have the what-the-system-is data model that supports thinking about a bank with its accounts, and the what-the-system-does algorithm model for transferring funds between accounts.

article at Artima about DCI

2.1. Methodless Roles, Methodful Roles and Classes

The DCI architecture represents what objects are able to do with the so called "Roles". Roles are further separated in "Methodless Roles" (aka intefaces or pure abstract classes) and the so called "Methodful Roles" (implementations of those interfaces, that do real stuff).

In an IDE, for instance, files can be saved, printed, opened, or edited. Packages and Projects can be cleaned, built, packaged and deployed. All those things that an object (such as a file) can do are represented with methodless roles, and are implemented with methodful roles.

Classes, instead, are used to indicate what objects are (using inheritance) and how they relate to other classes (how they are composed of other classes).

In an IDE, for instance, Java Projects implement the Project interface, and are composed of SourceGroups and Sources, that contain folders with Java files and other resources.[1]

2.2. Methodless Roles in the NetBeans Platform: Cookies and plain Java interfaces

Figure 1. Data representation in the NetBeans Platform

Data representation in the NetBeans Platform
(click to enlarge)

When programming with the NetBeans Platform you use plain Java interfaces to represent Methodless Roles, this is, for representing what objects are able to do.

There're different methodless roles in the NetBeans Platform, such as the Close cookie, the Edit cookie, and Save cookie, among others[2]. Note that these "methodless roles" are just plain Java interfaces, and that they don't actually do anything at all (because these are just plain interfaces and have no methods).

Those "Methodless Roles" just specify methods you can use for performing things. Methodless Roles define an API for you to perform things on objects, without actually having any code in them (because they're plain Java interfaces).

Note that this separation between methodless roles (APIs) and methodful roles (implementations of those APIs) have a big impact in mainteinance, as you can build the implementations and the APIs separately. It also makes things more flexible, because you can modify the implementations (the methodful roles) without modifying the classes and the methodless roles. This separation between compiling what-objects-are and what-objects-do has big implications in C++ projects, for instance.

2.3. Methodful Roles in the NetBeans Platform

Of course, those "methodless roles" do nothing at all. You have to implement those roles with real code. The actual implementation of "methodless roles" are called "methodful roles" in the DCI Architecture.

In the NetBeans Platform you just have to implement those special "Cookies" or interfaces with real code. For instance, you could have a "FileSaveCookie" that saves files. You don't really worry about what the file is (it can be a Java file, or a Ruby file): you just use a "FileSaveCookie" to save a file. This clearly separates what an object is (a Java file, or a Ruby file) from what an object does (saving itself).

If you want to save a project then you use a different implementation (a different methodful role), that will probably seek for unsaved files in the Project folders, and saves them all in case of need.

As an example: a quick Google search shows more than 700 different methodful roles of the "SaveCookie" methodless role out there in the Internet!

2.4. Classes: what objects are

So we've seen how the NetBeans Platform allows a clear separation from what objects are and what objects do.

To represent what objects are you just use plain Java inheritance as you have always done. So you can have, for instance, a Project interface (representing a generic Project) and a J2SEProject class (representing a J2SE Project, that is a Project), or a RubyProject class (representing a Ruby project, which is a NetBeans Project).

Or you can have a base DataObject class, that you can then extend to represent a Java file (a JavaObject) or a Ruby file (a RubyDataObject class).

The NetBeans Platform also separates what objects are from how objects are represented visually. A Project, for instance, is usually represented as a set of source folders with packages and files, and a set of folders with libraries, and another folder with unit test files, etc. In the NetBeans Platform, you represent how objects are visualized using Nodes. For more on this you can see this tutorial

2.5. Objects: mixing what-an-object-is and what-an-object-can-do

An object in the DCI Architecture is represented with both classes and roles. An object in the DCI terminology represents what the object is and what the object is able to do. But, how do you glue classes (a JavaDataObject class representing a Java file) with roles (SaveCookie and CloseCookie implementations)?

The very first approach could be to use multiple inheritance for this, but this is not possible in Java: a hypothetical "JavaDataObject" that extends "DataObject", could not extend simultaneously our methodful roles "JavaDataObjectSaveCookie" and "JavaDataObjectCloseCookie".

If we were using C++ instead of Java we could then use multiple inheritance, and make the "JavaDataObject" extend both "DataObject" and "JavaDataObjectSaveCookie" and "JavaDataObjectCloseCookie". We could abuse inheritance to mix both what an object is and what an object does. But this would lead to a bloated design, with a lots of inheritance dependencies that would make our compilation process (and our mainteinance effort) a real pain in the neck.

The NetBeans Platform uses The NetBeans Lookup Library for solving this problem of mixing what objects are and what objects do. Basically you have an object (the lookup) that holds all the methodful roles (such as "JavaDataObjectSaveCookie" or "JavaDataObjectCloseCookie") and you make all your "JavaDataObjects" return this "lookup" object. You can later query the object asking it what it can do, like this:

      // Our methodless role is the SaveCookie class
      Class methodlessrole = SaveCookie.class;

      // This is our object
      JavaDataObject object = ...

      // Get the object's lookup and lookup the seek for the save behaviour...
      // Note: This returns an instance of JavaDataObjectSaveCookie 
      SaveCookie methodfulrole = object.getLookup().lookup( methodlessrole );

      // Now that we have the methodful role we just use its API

Now, isn't that easy!? The NetBeans Lookup Library is really useful, isn't it?

2.6. Summary

The NetBeans Platform allows us to separate what objects are (using inheritance and composition) from what objects do[3]

You represent what an object can do with a set of "Methodless Roles" or interfaces ("cookies" in the old terminology). So you can have a "SaveCookie" for saving things, a "PrintCookie" for printing, a "CompileCookie" for compiling, etc.

You then implement those cookies creating "Methodful Roles" that know how to save a file, or how to save a project, or how to save an image.

You then bundle what an object can do inside a "Lookup bag", and make your object return it. You query this "lookup bag" containing methodful roles, and see if it has a "SaveCookie", for saving your files or projects.

[1] Of course NetBeans Projects are much more complex than this simplification, but hey, I don't want to bother you with boring internals. The idea is that you build what-classes-are with usual classes and interfaces, as you have always done.

[2] There're tons of "methodless roles" in the NetBeans Platform, and most of them don't have a "Cookie" suffix. The "Cookie" suffix is there for historical reasons, as originally methodless roles were built deriving from the Cookie interface, much before the DCI Architecture was invented.

Some other examples of "methodless roles" are, for instance, the LogicalViewProvider, that is an object that specifies that a Project can be represented visually (the project can represent itself visually), or the SubprojectProvider that is a methodless role used to indicate that a Project can have other Subprojects.

[3] And how objects are represented using Nodes too!