【问题标题】:How to change multiple main variables at the same time in Java如何在 Java 中同时更改多个主变量
【发布时间】:2016-04-13 15:37:40
【问题描述】:

在我对Java的理解中,最常见的设置类对象实例变量的方式有:

  1. foo.setFooStuff(bar); // 在类里面放一个setter方法
  2. foo = modifyFooStuff(foo, bar); // 传递并返回整个对象

假设我的 main() 有一个 bigA 类的对象,它包含一个 littleA 类对象的集合(其中包含实例变量),还有一个 bigB 类的对象,它包含一个 littleB 类对象的集合(它们有不同的来自 littleA 的实例变量)。如何编写一个方法来同时修改一个或多个 littleA 和 littleB 对象的实例变量?

(注意:我怀疑这是一个常见问题,但我搜索并没有找到它。也许我使用了错误的术语。)

编辑:更具体的例子:假设我正在制作大富翁。玩家有钱(各种面额)和财产(有些有房子)。她想将一些物业升级为酒店。钱必须加减,房屋和旅馆也是如此。我知道如何在传递引用语言中做到这一点,但不使用传递值,除非我将整个游戏状态变成一个巨大的对象并传递它,这看起来像是大量的内存洗牌,基本上和使用全局变量一样,这很糟糕,对吧?

【问题讨论】:

    标签: java methods scope


    【解决方案1】:

    如果我正确理解您的问题,您可以在 bigA/bigB 类上编写一个方法,该方法采用您要设置的值,然后遍历 littleA/B 对象的集合,随时设置实例变量。喜欢:

    // Assuming Foo has a member collection of smallFoo
    Foo A = new Foo();
    // do stuff that populates the collection of smallFoo in A
    A.setSmallFooZipCode("23444");
    

    public void setSmallFooZipCode(String zip_ {
        // for thisSmallFoo in smallFoo
            thisSmallFoo.setZip(zip);
        // end for
    )
    

    【讨论】:

      【解决方案2】:

      对象(包括您的容器对象)应该代表一些东西——从 A/B 的角度来考虑它们会让这有点困难。

      最重要的是,如果您总是同时修改两个类中的一个属性,我会建议这是一种非常糟糕的代码气味......

      我想不出我会用这种方式建模的任何东西,所以很难想出一个例子。 A 和 B 应该包含在父 ab 类中(并且该类应该具有属性),或者 a 和 b 应该是相同的接口——在任何一种情况下,它们都将进入父容器中的单个集合。

      也就是说,你应该在父容器对象上有一个方法来完成这项工作。在大多数情况下,它不应该是像“setAttribute...”这样的方法,而应该是像“doAction”这样的方法。换句话说,如果您的容器是一个“牧群”并且它包含一群大象,那么您将告诉牧群移动到某个位置并让牧群对象向每只大象发送一条消息,告诉它去哪里。

      如果您从“要求一个对象为您做某事”的角度来考虑方法,而不是对一个对象进行操作,这有助于使其中一些决策变得更加容易。

      【讨论】:

        【解决方案3】:

        您只需将BigABigB 封装在另一个对象中:

        class BigWrapper {
            private BigA bigA;
            private BigB bigB;
        
            public void someMethod() {
                bigA.someMethod();
                bigB.someMethod();
            }
        }
        

        BigA 内的someMethod() 将修改LittleA 实例。 BigB 也一样:

        class BigB {
            private LittleA[] littles;
        
            public void someMethod() {
                //do something with the littles
            }
        }
        

        当然,此解决方案不允许您指定 Little 要定位的实例,以及不允许您指定应该执行哪种行为(通过 littles 调用哪个特定方法)。

        如果您想要这种灵活性,请使用回调:

        interface Little { }
        class LittleA implements Little { }
        class LittleB implements Little { }
        
        interface Callback<T extends Little> {
            void perform(int currentIndex, T currentLittle);
        }
        
        class CallbackHandler<T extends Little> {
            private int[] indexes;
            private Callback<T> callback;
        
            public CallbackHandler(int[] indexes, Callback<T> callback) {
                this.indexes = indexes;
                this.callback = callback;
            }
        
            public void perform(T[] littles) {
                for(int i = 0; i < indexes.length; i++) {
                    int index = indexes[i];
                    callback.perform(i, littles[index]);
                }
            }
        }
        
        class BigWrapper {
            private BigA bigA;
            private BigB bigB;
        
            public BigWrapper(BigA bigA, BigB bigB) {
                this.bigA = bigA;
                this.bigB = bigB;
            }
        
            public void perform(CallbackHandler<LittleA> aCallback, CallbackHandler<LittleB> bCallback) {
                bigA.perform(aCallback);
                bigB.perform(bCallback);
            }
        }
        
        class BigA {
            private LittleA[] littles;
        
            public BigA(LittleA[] littles) {
                this.littles = littles;
            }
        
            public void perform(CallbackHandler<LittleA> callback) {
                callback.perform(littles);
            }
        }
        
        class BigB {
            private LittleB[] littles;
        
            public BigB(LittleB[] littles) {
                this.littles = littles;
            }
        
            public void perform(CallbackHandler<LittleB> callback) {
                callback.perform(littles);
            }
        }
        

        CallbackHandler 将实际回调映射到您要定位的索引。

        所以你首先要创建回调:

        Callback<LittleA> aCallback = (currentIndex, currentLittle) -> {
            //do what you want to the littles
        };
        

        然后将其传递给CallbackHandler,它允许您指定要定位的索引:

        int[] indexes = { 0, 1, 2 };
        CallbackHandler<LittleA> aCallbackHandler = new CallbackHandler<>(indexes, aCallback);
        

        BigWrapper 公开了一个perform(CallbackHandler&lt;LittleA&gt;, CallbackHandler&lt;LittleB&gt;),因此您可以将处理程序传递给该方法。

        MCVE 看起来像:

        public static void main(String[] args) {
            LittleA[] littleA = {
                new LittleA(),
                new LittleA(),
                new LittleA()
            };
            LittleB[] littleB = {
                new LittleB(),
                new LittleB(),
                new LittleB()
            };
            BigA bigA = new BigA(littleA);
            BigB bigB = new BigB(littleB);
            BigWrapper big = new BigWrapper(bigA, bigB);
        
            Callback<LittleA> aCallback = (index, little) -> {
                //...
            };
            Callback<LittleB> bCallback = (index, little) -> {
                //...
            };
        
            CallbackHandler aCallbackHandler = new CallbackHandler(new int[] { 2, 3, 4 }, aCallback);
            CallbackHandler bCallbackHandler = new CallbackHandler(new int[] { 5, 6, 7 }, bCallback);
        
            big.perform(aCallbackHandler, bCallbackHandler);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-08-18
          • 1970-01-01
          • 2014-05-21
          • 2016-11-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多