基于状态的实体处理的设计模式
Design pattern for state-based entity handling
我的问题是什么应该是最适合我的情况的 OOP 解决方案和正确的设计模式。我们有一个用户实体,多个帐户实体属于该用户。帐户实体可以有多个状态,我们可以对帐户执行多个操作。这些操作的结果基于帐户实体的状态。
我有以下主要基于开关的代码(有时它看起来像一些“如果”)。想改但是找不到合适的设计模式
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);
}
我知道这个问题一定有更好的实现。还有哪些其他设计模式适合此设置?
更新
我在主题中发现了几篇有趣的文章:
How to implement a FSM - Finite State Machine in Java
如果我对问题的理解正确,那么有必要根据其状态应用一些操作。
如果为真,那么我们可以使用工厂模式来获取可以执行某些操作的所需对象。 state和action的映射可以放到HashTable
.
让我们看一个代码示例。我将通过 C# 编写,但这段代码可以很容易地转换为 Java,因为语言有很多语法相似之处。
所以我们将有状态枚举:
public enum Status
{
Active,
Deleted,
Foo
}
和 AccountState
的状态
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
的映射器 class 到他们的 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
是什么,那么您可以创建一些 class,它只负责弄清楚对象的状态:
public class StatusManager
{
public Status Get()
{
return Status.Active; // or something another based on logic
}
}
这样做之后,你的classes将对应SOLID的单一职责原则。 Read more about single responsibility principle of SOLID here
太多 switch-/if-Statements 表明代码有“工具滥用者”的味道(请参阅 M. Fowler“重构”)。使用多态机制来解决这个问题。
https://refactoring.guru/smells/switch-statements
我的问题是什么应该是最适合我的情况的 OOP 解决方案和正确的设计模式。我们有一个用户实体,多个帐户实体属于该用户。帐户实体可以有多个状态,我们可以对帐户执行多个操作。这些操作的结果基于帐户实体的状态。
我有以下主要基于开关的代码(有时它看起来像一些“如果”)。想改但是找不到合适的设计模式
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);
}
我知道这个问题一定有更好的实现。还有哪些其他设计模式适合此设置?
更新
我在主题中发现了几篇有趣的文章:
How to implement a FSM - Finite State Machine in Java
如果我对问题的理解正确,那么有必要根据其状态应用一些操作。
如果为真,那么我们可以使用工厂模式来获取可以执行某些操作的所需对象。 state和action的映射可以放到HashTable
.
让我们看一个代码示例。我将通过 C# 编写,但这段代码可以很容易地转换为 Java,因为语言有很多语法相似之处。
所以我们将有状态枚举:
public enum Status
{
Active,
Deleted,
Foo
}
和 AccountState
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
的映射器 class 到他们的 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
是什么,那么您可以创建一些 class,它只负责弄清楚对象的状态:
public class StatusManager
{
public Status Get()
{
return Status.Active; // or something another based on logic
}
}
这样做之后,你的classes将对应SOLID的单一职责原则。 Read more about single responsibility principle of SOLID here
太多 switch-/if-Statements 表明代码有“工具滥用者”的味道(请参阅 M. Fowler“重构”)。使用多态机制来解决这个问题。 https://refactoring.guru/smells/switch-statements