Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从状态类访问上下文类的私有字段_Java_Design Patterns_Encapsulation_State Pattern - Fatal编程技术网

Java 从状态类访问上下文类的私有字段

Java 从状态类访问上下文类的私有字段,java,design-patterns,encapsulation,state-pattern,Java,Design Patterns,Encapsulation,State Pattern,我对状态模式实现感到困惑。在这种模式下,我们应该将状态管理提取到单独的类中。乍一看,如果。。。或者…在域实体内部构造,这真的是一个强大的优势。我们可以将所有条件检查移动到状态类中,并清除域实体类 但是如何在不违反封装原则的情况下修改封装在域对象中的数据呢 例如,考虑帐户< /代码>实体。简单地说,它有两种可能的状态-活动和被阻止以及存款和取款方法 在国家模式下,我们应该把存款和取款的责任委托给国家阶级 但是我们如何修改AccountState实现中的money和state字段呢?我只看到了我有公

我对状态模式实现感到困惑。在这种模式下,我们应该将状态管理提取到单独的类中。乍一看,如果。。。或者…在域实体内部构造,这真的是一个强大的优势。我们可以将所有条件检查移动到状态类中,并清除域实体类

但是如何在不违反封装原则的情况下修改封装在域对象中的数据呢

例如,考虑<代码>帐户< /代码>实体。简单地说,它有两种可能的状态-

活动
被阻止
以及存款和取款方法

在国家模式下,我们应该把存款和取款的责任委托给国家阶级

但是我们如何修改
AccountState
实现中的
money
state
字段呢?我只看到了我有公众支持的方式。但它违反了封装原则。通过这种方法,我还可以将私有字段更改为公共字段

代码示例:

类帐户{
私人货币;
私人帐户国家;
公共帐户(){
这是0.money=0;
this.state=new Active();
}
公共作废保证金(整笔金额){
本.状态.存款(本,金额);
}
公开作废取款(整笔金额){
本.状态.提取(本,金额);
}
public int getMoney(){
归还这笔钱;
}
公共帐户状态getState(){
返回此.state;
}
}
接口帐户状态{
公共无效存款(账户,整数金额);
公共作废取款(账户,整数金额);
}
类活动实现AccountState{
公共无效存款(账户,整数金额){
//如何在不使用设置器和公共字段的情况下更改帐户货币和状态?
}
公共作废取款(账户,整笔金额){
if(account.getState()instanceof Blocked){
抛出新的RuntimeException(“无法取款。帐户被阻止”);
}

if(account.getMoney()-amountPublic setters(或通常不考虑访问修饰符的实际setters)不要违反封装。封装意味着我们设置了类,这样只有类中带有变量的方法才能引用实例变量。在正确封装的类中,调用方需要使用这些方法才能修改类字段。

Public setter(或实际上,不管访问修饰符如何,通常都是setter)不要违反封装。封装意味着我们设置了类,这样只有类中带有变量的方法才能引用实例变量。在正确封装的类中,如果调用方希望修改类字段,则需要使用这些方法。

要仅允许从特定类调用,可以使用反射

Java中的示例:

PHP中的示例:

要仅允许来自特定类的调用,可以使用反射

Java中的示例:

PHP中的示例: 我想:

  • money
    移动到
    AccountState
    (在本例中,
    AccountState
    主要使用
    money
    操作)
  • 提供一种按照您规定的方式操纵
    账户的方法。这可以通过类似
    账户#交易(字符串标签,双倍金额)
    的方法,允许您在不暴露会员的情况下操纵余额
  • 删除AccountState作为冗余类,因为类的字段表示对象的状态
第二种方法也可以通过函数API实现,但不要将类成员的易变性与破坏封装混为一谈;封装的目的是禁止不必要的行为(如任意数学或访问内部集合)。这可以防止类进入错误状态。

我会:

  • money
    移动到
    AccountState
    (在本例中,
    AccountState
    主要使用
    money
    操作)
  • 提供一种按照您规定的方式操纵
    账户的方法。这可以通过类似
    账户#交易(字符串标签,双倍金额)
    的方法,允许您在不暴露会员的情况下操纵余额
  • 删除AccountState作为冗余类,因为类的字段表示对象的状态

第二种方法也可以通过函数API实现,但不要将类成员的易变性与破坏封装混为一谈;封装的目的是禁止不必要的行为(如任意数学或访问内部集合)。这可以防止类进入错误状态。

解决此问题的方法有很多,具体取决于每个状态实例需要执行的操作。在这个特定示例中,我将把
money
的字段值传递到
AccountState
中,而不是整个
Account
对象中

下面是一个使用枚举的示例,但很明显,它可能是两个单独的类,并带有一个接口

public class Account {
    private int balance = 0;
    private AccountState currentState = AccountState.ACTIVE;

    public int deposit(int amount) {
        balance = currentState.deposit(balance, amount);
        return balance;
    }

    public int withdraw(int amount) {
        balance = currentState.withdraw(balance, amount);
        return balance;
    }

    public AccountState activate() {
        this.currentState = AccountState.ACTIVE;
        return currentState;
    }

    public AccountState block() {
        this.currentState = AccountState.BLOCKED;
        return currentState;
    }

    enum AccountState {
        ACTIVE {
            @Override int deposit(int balance, int amount) {
                return balance + amount;
            }
            @Override int withdraw(int balance, int amount) {
                int newBalance = balance - amount;
                if (newBalance >= 0) {
                    return newBalance;
                }
                throw new IllegalArgumentException("Withdrawal amount is greater than balance.");
            }
        },
        BLOCKED {
            @Override int deposit(int balance, int amount) {
                throw new UnsupportedOperationException("Account is blocked.");
            }
            @Override int withdraw(int balance, int amount) {
                throw new UnsupportedOperationException("Account is blocked.");
            }
        };
        abstract int deposit(int balance, int amount);
        abstract int withdraw(int balance, int amount);
    }
}

OP中的代码很难应用OOP模式的一个线索是业务逻辑方法(
存款
提取
)return
void
。除了使用
void
方法进行过程编程之外,很难做任何事情。让您的方法返回适当的值,这样您就可以更轻松地组成自然交互的类。

解决此问题的方法有很多,具体取决于您需要每个状态实例执行的操作在这个特定的例子中,我将把
money
的字段值传递到
AccountState
而不是整个
Account
对象中

下面是一个使用