仅使用不可变对象的实际真实Java应用程序

时间:2018-03-08 12:34:29

标签: java immutability

互联网上有很多很多页面描述了如何用Java编写不可变类。互联网使这个特定的主题非常紧张。我很擅长。

无论不变性原则的优点如何,我都无法找到一个很好的Java示例,说明如何在现实世界中应用这一原则,或者达不到那个崇高目标,在不仅仅是不可变对象本身!

显然,没有状态变化的应用程序本质上是无用的。

因此,不变性原则说“返回一个相同类型的新不可变对象,以表示状态改变后对象的新状态”。忽略这种方法的好处或其他方面,我的问题是,新对象一旦创建会发生什么?任何其他对象如何挂在它上面而不必自己改变状态?

所以我特别感兴趣的是如何构建新的不可变对象以替换旧的不可变对象在Java中作为一种可行的机制来处理应用程序状态的变化。

我不明白新的不可变对象的客户端如何保持对象而不必自己更改状态。这是我理解这个问题试图克服的差距。

这里有一些灵感......你将如何重组这个应用程序以避免可变性?

public class MyVideoGameApp extends Application {
    private int highScore = 0;
    public void newGame() {
        GameEngine game = new GameEngine((r) -> {
            highScore = Math.max(highScore, r.getScore());
        });
        game.start();
    }
    public static void main(String args[]) {
        launch(args);
    }
}

1 个答案:

答案 0 :(得分:0)

您好我会尝试给您一个真实的例子。让我们假设我们有一个银行和帐户。我们还有在帐户中运行的交易。现在让我们说这些交易发生了一天,这一天需要关闭,所有交易都反映在账户上。

交易顺序将改变账户和余额的状态,有时会导致收费,这将另外影响余额。如果余额低于限额,帐户可能会进入冻结状态。每次交易后,您的帐户都会进入一个独特的状态。这种状态与其原始状态不同。

通过拥有帐户的所有状态,您可以在交易错误的情况下随时回到之前的状态。

这是上面的元代码示例。元代码非常通用,但问题就在于此。

class Account {
    // can be blocked account, Debit, Credit
    ACCOUNT_TYPE state;   

    public Account applyTransaction(Transaction transaction) {
      // returns new Account with transaction applied
    }

}

class TransactionProcessingJob {

 public processTransactions(List<Transaction> transactions,Account accountToProcess) {


   List<Account> allAccountStates =  transactions.stream().map(t->accountToProcess.processTransaction(t)).collect();

  Account lastState = allAccountStates.getLast();

  // do whatever you want to do.
  //rewind if you want
 }

} 

基于上次编辑,不确定您想要实现的目标,但这是一个改进可修改性的修改:

  public class MyVideoGameApp extends Application {


    public void newGame() {
        Score allTimeHighScore = Normaly it is durable somewhere;  
        Game game = () -> {
                            Random rand = new Random();
                            return Score.scoreOf(rand.nextInt());   
                            };
        GameEngine gameengine = new GameEngine(game);
        Score finalScore = gameengine.play();

        writeToDurableLocation (Score.max(allTimeHighScore, finalScore);

    }
    public static void main(String args[]) {
        launch(args);
    }
}

   @FunctionalInterface
public interface Game {

    public Score play();

}

        public class Score {

            private final int score;

            private Score(int score) {
                this.score = score;
            }

            public static Score scoreOf(int score) {
                return new Score(score);
            }

            public boolean equals(Score score) {
                return this.score == score.score;
            }


            public static Score max(Score scoreLeft, Score scoreRight) {
                return scoreLeft.score >= scoreRight.score ? scoreLeft : scoreRight;    
            }

        }