Bogado.net

Facet oriented programming

OO programming is full of concepts that at first seem unrelated but they share some similarities when observed closely. While it might be a good thing that we think and use on them as different concepts, there be advantages in seeing them as a single, unified concept.

I will explore this unification by observing each concept separately and how they are similar.

Interfaces

In java interfaces are a kind of contract that an object promises to fulfil. But the same concept is present almost everywhere, from header files declarations to opaque ODL service definitions

A collection of methods that instances must have an implementation for. The advantage is that this contract is a definitive separation of implementation and the contract.

Interfaces function as a view for the object. In a way it exposes a facet of it to the exterior, without exposing any other part of it. The same instance can be seen with different glasses when it is casted into an interface. So you can think of implemented interfaces as facets of the same object.

I will explore here the concept of facets.

facet

I will define facet as an exposed way that an object have within different contexts. Depending on what this context is and what parts of the objects are exposed by the facet represent different OO or language concepts.

classes or types

When we define a class, we are defining a facet, that other classes, methods can see. In fact when we define those classes we are usually defining three or more different implicit facets of the object.

private access control

The private access can be seen as a facet. It is the super user facet of the object in the sense that if a context has private access it can do everything that can be done with the instance.

public access control

The public access facet can be seen as the interface that anonymous contexts have to the class. In C or C++ is this can be thought as the forward declaration of the type, that lives in the header file as well as the actual public declarations..

other accesses levels

It’s easy to see that other access modifier bare the same facet aspect associated with them. The only variation is where they are exposed.

inheritance

Inheritance is a special case of interfaces that carry implementation along. As is the case of interfaces when a class inherits from another you are also defining that the base class is a different aspect of the class.

Inner classes

In Java, non static inner classes can be seen as aspects of the original instance. Since they carry an implicitly reference to the original instance and even have privileged access to it, but exposes only it’s own interface.

example

Let’s explore the concept with a more expressive java bean.

/* PersonReader.java */
public interface PersonReader {
    String getName();
    String getSurname();
}

/* PersonWriter.java */
public interface PersonWriter {
    void setSurname(String newSurname);
    void setName(String newName);
}

/* PersonId.java */
public interface PersonId {
    void getId();
    // This class should also expose the comparisson bits, like `equals` and `hashCode`.
    // Those were ommited to simplify this example.
    PeopleReader getReader();
    PeopleWriter getWriter();
}

/* Person.java */
public class Person implements PersonReader, PersonWriter, PersonId {
    private String name;
    private String surname;
    private int id;

    public static PersonId buildPerson() {
        return new Person();
    }

    String getName() {
        return name;
    }

    String getSurname() {
        return surname;
    }

    void setName(String newName) {
        name = newName;
    }

    void setSurname(String newSurname) {
        surname = newSurname;
    }

    public getId() {
        return id;
    }

    public PeopleReader getReader() {
        return this;
    }

    public PeopleWriter getWriter() {
        return this;
    }

    // The constructor is private.
    private Person() {  }
}

This version uses interfaces to define the different aspects of the object, the standard aspect is available is the person identifier. This facet gives you access to the other aspects.

Notice that the usual public top level class is not exposed directly to rest of the application, the application can only construct it through the builder that returns a PersonId. The Person class is a type of "super user" access to the underlying object, this could be used for instance to add test accessibility that are not exposed to the rest of the application.

The PersonId is a gateway to the different aspects that might be needed by the code and can also centralize the synchronization if that is necessary.

The example bellow uses sub-classes to achieve a similar effect. The advantage of being able to use a single file. This version lacks the "super user" aspect, in this simple bean class that don’t require testing this can be an advantage as the whole package is simpler.

class Person {

    private String name;
    private String surname;
    private int id;

    public class Reader {

        String getName() {
            return name;
        }

        String getSurname() {
            return surname;
        }
    }

    public class Writer {
        void setName(String newName) {
            name = newName;
        }

        void setSurname(String newSurname) {
            surname = newSurname;
        }
    }

    public Reader getReader() {
        return new Reader();
    }

    public getWriter() {
        return new Writer();
    }

    public getId() {
        return id;
    }
}

why?

Separating different aspects of an object can be an useful abstraction that could help to make the code safer, by giving the reader more insight on how each component is using the object and making it harder to misuse the data.

This separation can also make your code easier to read, by making explicit the intentions on how each part of the application is using the object. Will it read only? Does it need to update it? Do you need an apple or just a fruit is enough?

This might look like it’s going on the opposite direction of the single concern, and it may as well be. I do believe that sometimes some concerns might belong in the same entity. Making differnt aspects from an central data type is a way to create this separation, without the need to break the underlying entity into too much abstraction.