基于状态的实体处理的设计模式



我的问题是什么应该是最OOP的解决方案和适合我的情况的设计模式。我们有一个用户实体,多个帐户实体属于该用户。账户实体可以有多个状态,我们可以对账户执行多个操作。这些操作的结果基于帐户实体的状态。

我有以下代码,它主要基于switch(有时看起来像一些"if"(。我想更改它,但找不到合适的设计模式。

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
}
}

我真的很想重构这些代码,我担心一旦我们的服务增长,它就会包含更多的";魔术;并且将难以维持。如果我们想引入一个新的州,那几乎是不可能的。

我的初级思想认为,我应该有状态对象,以伪代码风格实现所有操作:

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
}
}

和:

class ActiveState extends AccountState {
@Override
public Account delete(Account account) {
//implementation
}
@Override
public Account activate(AccountInfo) {
// implementation
}
}

和:

interface AccountState {
Account activate(AccountInfo);
Account delete(AccountInfo);
}

我知道这个问题必须有一个更好的实施方案。其他哪些设计模式适合此设置?

更新

我发现了一些有趣的文章可以在主题中阅读:

如何在Java 中实现有限状态机

当你有更复杂的状态处理

如果我正确理解了这个问题,那么就有必要根据它的状态应用一些操作。如果它是真的,那么我们可以使用Factory模式来获得所需的对象,该对象可以执行一些操作。状态和动作之间的映射可以放入CCD_ 1中。

让我们来看一个代码示例。我将通过C#编写,但这段代码可以很容易地翻译成Java,因为语言有很多语法相似之处。

因此,我们将有状态枚举:

public enum Status 
{ 
Active,
Deleted,
Foo
}

CCD_ 2 的状态

public abstract class AccountState
{
public abstract void ExecSomeLogic();
}
public class ActiveState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}
public class DeletedState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}
public class FooState : AccountState // "extends" instead of ":" in Java
{
public override void ExecSomeLogic()
{
}
}

然后我们需要Status的映射器类到它们的AccountState:

public class StatusToAccountState 
{
public Dictionary<Status, AccountState> AccountStateByStatus { get; set; } = 
new Dictionary<Status, AccountState>() // HashMap in Java
{
{ Status.Active, new ActiveState() },
{ Status.Deleted, new DeletedState() },
{ Status.Foo, new FooState() },
};
}

然后在你的服务中,你可以这样使用它:

void Delete(long id, Status status)
{
StatusToAccountState statusToAccountState = new StatusToAccountState();
AccountState accountState = statusToAccountState.AccountStateByStatus[status];
accountState.ExecSomeLogic();
}

如果有很多逻辑可以弄清楚对象的Status是什么,那么你可以创建一些类,它只对弄清楚对象状态有一个响应:

public class StatusManager
{
public Status Get() 
{
return Status.Active; // or something another based on logic
}
}

完成此操作后,您的类将符合SOLID的单一责任原则。阅读更多关于SOLID单一责任原则的信息

太多开关-/if语句指示代码气味"工具滥用者";(参见M.Fowler的"重构"(。使用多态性机制来解决这个问题。https://refactoring.guru/smells/switch-statements

最新更新