My question is about what should be the most OOP solution and the right design pattern for my situation. We have a user entity and multiple account entities belong to the user. Account entities can have multiple states and we can execute multiple operations on accounts. The outcome of these operations is based on the account entity's state.
I have the following code which is based mostly on switch (sometimes it looks like a few "if"). I would like to change it but cannot find the right design pattern.
enum Status {
ACTIVE, INACTIVE, DELETED;
}
@Entity
class Account {
private long id;
private long userid;
private Status status;
//...
}
class AccountService{
Account delete(long id) {
//...
if (accountInfo.getSatus() == DELETED) {
throw new IllegalOperationException();
}
if (accountInfo.getStatus() == ACTIVE || accountInfo.getStatus()) {
accountInfo.setStatus(DELETED);
accountInfoRepository.save(accountInfo);
}
}
Account create (Account account) {
// various operations based on state
}
}
I really want to refactor these codes, I fear that as soon as our service grows it will contain more "magic" and will be hard to maintain. And if we would like to introduce a new state it will be nearly impossible.
My junior mind thought that I should have state objects which would implement all the operations, in pseudo-code style:
class AccountService {
private StateFactory stateFactory;
private AccountRepository accountRepository;
Account delete(long id) {
final Optional<Account> account = accountRepository.findById(id);
Account deletedAccount = account.map(stateFactory::getByState)
.map(accountState -> accountState.delete(account))
.orElseThrow(() -> new IllegalOperationException());
return accountRepository.save(deletedAccount);
}
Account create (Account account) {
// various operation based on state
}
}
and:
class ActiveState extends AccountState {
@Override
public Account delete(Account account) {
//implementation
}
@Override
public Account activate(AccountInfo) {
// implementation
}
}
and:
interface AccountState {
Account activate(AccountInfo);
Account delete(AccountInfo);
}
I know there must be a better implementation for this problem. Which other design patterns are suitable for this setup?
UPDATE
I have found a few interesting articles to read in the topic: