Comments

11/20/05: Refactoring Combo: Extract Method Object

Let's say you've got a big class with a lot of methods -- a dispatcher or controller, say, that's gotten a bit out of control. The methods are real business methods (or at least they have business logic inside them), but they refer to several different entities, so you're not sure they belong on any given entity. But you want to get them out of the original class and into domain classes.

Moreover, these methods all do things in nearly the same way. In a controller, for instance, since they're all responding to different incoming events, they probably have similar code for handling exceptions, logging, maybe setting up and committing/rolling back database transactions, etc. This is a lot of functional duplication you'd like to remove.

Sounds like it might be time for a Method Object [which is a step towards the Command Pattern. In an earlier version of this post I conflated the two, but they're distinct, and I should go revise the draft of the article to match.]

Usually a Command is used when you want to encapsulate the doing of something, without actually doing it right away. But in this case, we'll execute it immediately. Don't worry, it will carry its own weight by removing the business logic from the original object, and by being cleaner and more isolated, and thus more testable. It will also be set up so that you can do all the cool Command pattern tricks later if you want, like polymorphic dispatch or undo.

Before:

public Money withdraw(int accountNumber, Money amount) throws SessionException {
    try {
        Account account = accountService.findAccount(accountNumber);
        verifyBalance(account, amount);
        account.withdraw(amount);
        return account.getBalance();
    }
    catch (AccountServiceException e) {
        logger.log(e);
        throw new SessionException(e);
    }
}
After:
public Money withdraw(final int accountNumber, final Money amount) throws SessionException {
    return new Withdraw(accountNumber, amount, logger, accountService).execute();
}
...
class Withdraw extends AtmCommand<Money> {
    private final int accountNumber;
    private final Money amount;
    private AccountService accountService;

    public Withdraw(int accountNumber, Money amount, Logger logger, AccountService accountService) {
        super(logger);
        this.accountNumber = accountNumber;
        this.amount = amount;
        this.accountService = accountService;
    }

    protected Money doExecute() throws AccountServiceException, SessionException {
        Account account = accountService.findAccount(accountNumber);
        verifyBalance(account, amount);
        account.withdraw(amount);
        return account.getBalance();
    }
}

In this article on purpletech.com, I will walk through the precise sequence of steps to perform this refactoring in IntelliJ IDEA (version 5). There are some pretty fun keystroke combos you can use to make the whole thing relatively painless and automated. (Automating refactorings is better than just typing because it's less likely to introduce errors, it's got more stable intermediate points so you can safely stop halfway through, and most of all, because it makes you feel cool.)

Full article at: http://www.purpletech.com/articles/combos/extract-command.html

Comments made

http://www.wholesalesnapbac...

Rappers and music artists of all sorts are selling his or her designer label lines of hats to their adoring fans. Shows proudly display their name for their snapbacks, as do so very many professional sporting organizations.
03/13/12 20:17:38

Add comment

Sorry, but due to blog comment spam, I have to ask you to create an account before you post a comment. Please log in (using the form on the top right of the page) or click here to create an account: Create an account!