0

A problem I've come across and never really had a good answer for, is: what is the correct design pattern for creating or returning an object from another object, or multiple objects?

Traditionally I've just created a Factory and had the source as a argument:

#!/usr/bin/env groovy
class Foo {
    String bar
}

class FooFactory {
    Foo createFoo(Map mapWithBar) {
        Foo foo = new Foo()
        foo.bar = mapWithBar.get('bar')
        foo
    }
}

assert 'Hello, World!' == new FooFactory().createFoo(['bar': 'Hello, World!']).bar

Is factory really the correct name for this pattern?

What happens when you want to encapsulate pseudo-creational logic that has multiple possible sources, or possibly the object is even already created?

For example, say if bar is in a list of Strings (i.e. cli args), set bar from that, otherwise if Foo already exists in some data structure, use that foo, otherwise create a new Foo with a default bar:

#!/usr/bin/env groovy
class Foo {
    String bar
}

class FooFactory {
    Foo createFoo(List<String> args, Map mapContainingFoo, String defaultBar) {
        if (args?.size > 0) {
            def foo = new Foo();
            foo.bar = args[0];
            return foo;
        } else if (mapContainingFoo?.containsKey('foo')) {
            return mapContainingFoo.get('foo');
        } else {
            Foo foo = new Foo();
            foo.bar = defaultBar;
            return foo;
        }
    }
}

def fooFactory = new FooFactory();
assert 'args' == fooFactory.createFoo(['args'], ['foo': new Foo(bar: 'fromMap')], 'default').bar
assert 'fromMap' == fooFactory.createFoo(null, ['foo': new Foo(bar: 'fromMap')], 'default').bar
assert 'default' == fooFactory.createFoo(null, null, 'default').bar

Is there a better design pattern to encapsulate this logic? Is Factory the correct term? Is it even still a Factory since it isn't necessarily creating Foo?

Note that I'm only using groovy for ease of demonstration, I'm mainly concerned with the design pattern and not an idiomatic way of doing this in groovy.

1

Rest easy, Factory is the correct pattern/term.

One of many examples is: the AppFabric cache product has a DataCacheFactory class. The factory might new() up underlying objects establishing connectivity to the cache server; or utilize existing connected objects.

0

You did well choosing Factory pattern and the implementation seem fine to me (IMHO).

What happens when you want to encapsulate pseudo-creational logic that has multiple possible sources, or possibly the object is even already created?

As you know, Factory pattern hides the creation logic so that you don't have to repeat such logic all over the project. If the logic is too simple or too complex depends on the design (and this last depends on the requirements). In any case, the thing is to provide the responsability to the specific component/s.

Is it even still a Factory since it isn't necessarily creating Foo?

Yes, it's. Look at it from the point of view of the client (Factory consumer). You would be just providing the arguments in order to get a new Foo. That's it. What's going on under the hood is not your business.

Back to the example. I would suggest you some changes.

class Foo {
    String bar       
}

class FooFactory {
    Foo createFoo(List<String> args, Map mapContainingFoo, String defaultBar) {
        if (mapContainingFoo?.containsKey('foo')) {
            return mapContainingFoo.get('foo').clone();
        }
        def foo =new Foo();
        foo.bar = defaultBar;

        if (args?.size > 0) { 
            foo.bar = args[0];
        } 
        return foo;
    }
}

I guess it's a sample code, nevertheless, I have reordered the if-else block. If that matters.

The change that matters (IMO) is:

//If foo is not clonable, make a copy.
mapContainingFoo.get('foo').clone();

The reason is simple. When I call a Factory I expect a new brand object, untied from the input params.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.