Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

The Soon-to-Be-Hated Object Locator

DZone's Guide to

The Soon-to-Be-Hated Object Locator

What if the objects in the system appeared to exist at all times? Wouldn't that be cool? A slight modification of the hated Service Locator pattern gives you just that!

· Java Zone
Free Resource

The single app analytics solutions to take your web and mobile apps to the next level.  Try today!  Brought to you in partnership with CA Technologies

As more frequent readers of my blog might know, amongst my most recent interests were concepts like DCI Architecture, Domain-Driven Design, and the Service Locator pattern. I’ve been doing a lot of conceptual thinking about these topics and an interesting idea sprung in my head – an Object Locator! Caution: if you’re among the haters of Service Locator, you might not like this one.

A Bit of DCI

At the very roots of the DCI Architecture and, to some, Object Orientation lies the idea of a web of interconnected objects. You know, the objects exist somewhere in the system and work together to support end user’s goals. Here lies my first conceptual problem with our current approach to working with objects.

Most of the most important objects i.e. entities don’t actually exist in the system for the most part. Only when retrieved from a repository they come to existence and the access to that repository is not ubiquitous in the system. Only selected classes have the repository injected and can actually retrieve the objects.

My basic idea is that all of the objects in the system regardless of their type and identity should exist in the system at all times, or, at least, seem to exist at all times. If my object wants to talk to the mailing class, it should be just able to say: “Hey, Mailer! Send this email to this address please.” If it wants to talk to some random entity, then it should be easily able to say: “Hey, random entity! Tidy Java is the best programming blog on the planet!” All of this should be possible without injecting endless amounts of classes like repositories and similar.

A Bit of DDD

Now, let’s turn a bit into the DDD zone. In his great article series, Vaugh Vernon points out that aggregates should not directly reference each other. Instead, an aggregate should only hold an ID of the other object and use other means to get in touch with the object. It’s not that big of a hassle to avoid direct references and it both reduces coupling and greatly increases scaling.

In my idea, that ID is/should be enough to talk to the other object at any time. Unfortunately, in our current way of thinking, if my object only has the ID of another object (which could semantically be considered a valid reference to the object), it still cannot talk to it unless it has access to the damn repository.

Vaugh Vernon would probably suggest the usage of the actor model at this point, but this is not a satisfying solution for me. I hate complicating things. If I’m building a simple system right now, I want it to look like a simple system. If I need the superb scaling (and extra complexity) of the actor model later, I want to be able to add it later.

A Bit of Service Locator

As the last source of inspiration, I took the hated Service Locator pattern. It caught my attention because it allows us to dynamically resolve “service” dependencies in the whole system. This big, fundamental “flaw” of the pattern actually fits the idea of objects seeming to exist at all times.

I guess you guys see where I’m going with this…

The Object Locator

We could modify our Service Locator “pattern” to allow resolving all kinds of objects, not only the so-called services. That’s not really a big change. For many smaller applications, it would mean as much as exposing methods to retrieve objects by ID via the locator. A very basic implementation could look like this:

public class Objects {
    private static Mailer mailer;
    private static CustomerRepository customerRepository;

    public static Mailer mailer() {
        return mailer; // service
    }

    public static void setMailer(Mailer mailer) {
        Objects.mailer = mailer;
    }

    public static Customer customer(Long id) {
        return customerRepository.findById(id); // entity
    }

    public static void setCustomerRepository(CustomerRepository customerRepository) {
        Objects.customerRepository = customerRepository;
    }
}


This simple trick allows me to retrieve any kind of object I need at all times without carrying a bag of repositories around. Resolving an object to collaborate with is a matter of a simple method call:

public class Order {
    private Long number;
    private Long customerId;

    public Order(Long number, Long customerId) {
        this.number = number;
        this.customerId = customerId;
    }

    public void confirm() {
        // resolving an entity:
        customer(customerId).confirm(createConfirmation());
    }

    private OrderConfirmation createConfirmation() {
        return new OrderConfirmation(number);
    }
}
public class Customer {
    private String firstName;
    private String email;

    public Customer(String firstName, String email) {
        this.firstName = firstName;
        this.email = email;
    }

    public void confirm(OrderConfirmation orderConfirmation) {
        orderConfirmation.fill(firstName, email);
        // resolving a service:
        mailer().send(orderConfirmation);
    }
}


Obviously, it’s not as magical as it could be. In the end, I’m calling a method, instead of somehow referring to the object by name or something. But I think it’s close enough. Any object can talk to any other object. The persistence involved in resolving objects is hidden from their collaborators. It seems like the objects existed at all times.

If I wanted to scale my application by introducing a concurrency model like the Actor Model, I could simply extract an object’s interface and implement a proxy. The object locator is then changed to return the proxy and all of the class’ collaborators remain happily unconscious of the magic happening under the hood.

Before You Deem Me Crazy

I suppose that most of you can imagine what a crazy, big, unmaintainable mess this pattern could bring to any project. I’m in this group as well. I know how bad things could go with this. At the same time, things do not necessarily have to go this way. The key to preserving maintainability is strict scope control.

An object locator should never be global to the whole system. It would grow way too large and make working with the code almost impossible. It should span no more than a single component or a small microservice. For anything outside of that scope, the object locator should contain a service object responsible for communicating with other parts of the system.

The mailer object from the code example above could be an example of such a service. The whole mailing component could contain a lot of sophisticated logic, which is of no interest our current component. Therefore, the mailing component should have its own object locator and expose not more than a couple of interfaces. Since our component wants to communicate with the mailing component, our object locator is able to resolve the mailer as above.

Final Words

I don’t expect any of you to fall in love with the idea and start using it immediately. Far from it. At the same time, I think that the idea is interesting and I had a lot of fun working it out in my mind. I’m pretty sure that a team with a good set of skills in dependency management would be able to pull it off in a real system. I’m also pretty sure that there’s a ton of different ways to implement the concept of ever-existing objects without resorting to a locator. Maybe you can come up with one? :)

CA App Experience Analytics, a whole new level of visibility. Learn more. Brought to you in partnership with CA Technologies.

Topics:
dci architecture ,ddd ,service locator ,object locator ,java

Published at DZone with permission of Grzegorz Ziemoński, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}