ip696
ip696

Reputation: 7104

Template method and inheritance or composition

I have these classes:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Admin {
    private String name;
    private int age;
}

And I have some operations with template method pattern implementation. Base class with algorithm:

public abstract class Operation<T> {
    public void process(T t) {
        System.out.println(t);
        updateName(t);
        System.out.println(t);
    }

    protected abstract void updateName(T t);
}

Two children with implementation template method:

@Component
public class UserOperation extends Operation<User> {

    @Override
    protected void updateName(User user) {
        String newName = user.getName().toUpperCase();
        user.setName(newName);
    }
}

@Component
public class AdminOperation extends Operation<Admin> {

    @Override
    protected void updateName(Admin admin) {
        String name = admin.getName();
        StringBuilder builder = new StringBuilder();
        builder.append(name);
        StringBuilder reverse = builder.reverse();
        admin.setName(reverse.toString());
    }
}

My questions:

  1. How do I rewrite this code to use composition?

  2. Do I understand correctly that when using the template method, I attach to inheritance?

The template method is a great way to avoid duplication. But if it binds me to inheritance, what other ways are there to avoid code duplication? In my example, how can I use composition? (replace the template method with something else?)

Upvotes: 2

Views: 1878

Answers (2)

jaco0646
jaco0646

Reputation: 17164

1) How do I rewrite this code to use the composition?

The Strategy Pattern is one way. Essentially, you would reverse the relationship between data and operations by passing the operations into the data rather than passing the data into the operations. This is a fundamental change, because "real" objects (with state and behavior) are used instead of data classes.

2) Do I understand correctly that when using the template method, I attach to inheritance?

Yes, the Template Method Pattern is fundamentally based on inheritance.

Upvotes: 1

Maurice Perry
Maurice Perry

Reputation: 9658

Instead of template pattern you could have a proxy:

public abstract class Operation<T> {
    public abstract void updateName(T t);
}

public class OperationProxy<T> extends Operation<T> {
    private final Operation<T> delegate;

    public OperationProxy(Operation<T> delegate) {
        this.delegate = delegate;
    }

    @Override
    public void updateName(T t){
        System.out.println(t);
        delegate.updateName(t);
        System.out.println(t);
    }
}

Note that this would allow you to make class Operation and interface.

UPDATE

Another possibility is defining sequences of operations, and a print operation (even more code):

public interface Operation<T> {
    void updateName(T t);
}

public class OperationSequence<T> implements Operation<T> {
    private final Operation<T>[] steps;

    public OperationSequence(Operation<T>... steps) {
        this.steps = steps;
    }

    @Override
    public void updateName(T t){
        for (Operation<T> step: steps) {
            step.updateName(t);
        }
    }
}

public class PrintOperation<T> implements Operation<T> {
    @Override
    public void updateName(T t){
        System.out.println(t);
    }
}

You can now use the following code:

    Operation<MyClass> print = new PrintOperation<>();
    Operation<MyClass> seq = new OperationSequence<>(
            print, (t) -> {doSomethingWith(t);}, print);

Upvotes: 0

Related Questions