如何在Java中不使用全局变量而在两个类之间共享变量?

如何在Java中不使用全局变量而在两个类之间共享变量?,java,oop,variables,Java,Oop,Variables,假设我有两个对象灯光和灯光开关,我想做的是 打开灯开关,然后检查灯是否打开或关闭。在这种情况下,预期答案为“打开” 请注意,当开关打开时,共享变量名称current将设置为true,然后指示灯也将打开 我对这个问题感兴趣的是: 在这种情况下,Light和LightSwitch两个类如何在不使用全局变量的情况下共享变量值在这种情况下,共享变量是当前的? 如何在面向对象的概念中实现这个简单的问题? 预期输出或您喜欢的另一个输出,可以告诉我ok,指示灯打开/关闭: switch on: true

假设我有两个对象灯光和灯光开关,我想做的是

打开灯开关,然后检查灯是否打开或关闭。在这种情况下,预期答案为“打开”

请注意,当开关打开时,共享变量名称current将设置为true,然后指示灯也将打开

我对这个问题感兴趣的是:

在这种情况下,Light和LightSwitch两个类如何在不使用全局变量的情况下共享变量值在这种情况下,共享变量是当前的? 如何在面向对象的概念中实现这个简单的问题? 预期输出或您喜欢的另一个输出,可以告诉我ok,指示灯打开/关闭:

switch on: true       // This line just set variable `current` in `LightSwitch` class
Light is turned on    // This line just check that `current` variable in `Light` class is True or false 
switch on: false
Light is turned off

有几个选项,但一般来说,这种优雅的解决方案根本不使用全局变量,也不秘密使用它们:

单态模式

使singleton LightState或任何东西-在工厂类中使其构造函数私有,该工厂类在请求时返回单个静态LightState。然后,每当有人请求lightstate时,都会给他们相同的值

静态变量

只需在两个类中的一个类中创建一个静态私有getter变量,并让另一个类请求它

观察者模式

应用其他两种方法中的一种,但将在状态发生变化时通知正确代理的责任留给州政府;这样,代理不负责链接到状态,从而使链接更简单、更优雅

或者,观察者可以通知控制器代理,该代理随后将根据需要发生的任何动作采取相应行动,这意味着两个独立的元素可以完全不知道共享信息

继承权

Light是lightswitch的子类还是visa的子类?它取决于使用情况,但可能不是。但是,如果是这样,您可以创建一个受保护的静态变量,它们都可以访问。通过为这个状态创建一个最终的包装器对象,您可以确保nobobdy every将其切换出去,从而导致混乱的错误引用

直接连接

让灯光开关跟踪灯光。您仍然需要知道灯光状态何时从开关以外的其他方式发生变化,因此观察者模式仍然可以派上用场。

通常,每个灯光开关都连接到一个或多个灯光。我首先将Light实例传递给LightSwitch,并将其作为一个字段保存在switch中

private Light current;
public LightSwitch(Light light) {
  this.current = light;
  on();
}
public boolean isOn() {
  return current.isOn();
}
public void on() {
  current.setOn(true);
}
public void off() {
  current.setOn(false);
}
public String toString() {
  return isOn() ? "switched on" : "switched off";
}
那么你的主要目标可能是

LightSwitch switch = new LightSwtich(new Light());
System.out.println("Light is: %s%n", switch);
switch.off();
System.out.println("Light is: %s%n", switch);
产出将是

Light is: switched on
Light is: switched off

基本答案是,在OOP中,您不会共享这样的变量。OOP和其他模块化编程范例的一个要点是封装。对象可以根据其公共接口指定的修改或查询方式进行修改或查询。要修改对象的状态或更改其行为,必须调用属于该对象的方法之一。这样,对象可以完全控制自己的状态;它知道何时调用自己的方法,并且这些方法本身就能够修改对象的状态信息

拥有一个共享变量会毁掉这一切。如果一个变量在两个对象之间共享,那么当一个对象指定给该变量时,它可能会以另一个对象无法控制的方式修改另一个对象的行为。所以这是需要避免的

相反,其中一个对象需要调用另一个对象的方法。最有可能的是,如果你有一个打开灯开关的方法,它将需要打开灯。我认为,最直接的方法是在其构造函数中告诉LightSwitch它将打开什么灯:

public LightSwitch (Light light) { ... }
或者,如果它控制多个灯光

public LightSwitch(Light[] light) { ... } // or use a List or Set or whatever

然后构造函数将保存此引用,其打开方法将调用light.turnOn。这就是在面向对象编程中处理这个问题的方法,而不是使用共享变量。

无论是谁教你的,都会给你带来一些坏习惯,这会使Java编程和面向对象编程变得很难

你需要更好的封装。类似于

class Light {
    ...
    public void startCurrent(){...};
    public void stopCurrent(){...};
    public boolean isOn();
}

class Switch {
    Ligh target;
    public Switch(Ligh target) {...}

    public clickOn(){target.startCurrent();}
    public clickOff(){target.stopCurrent();}
}

// now wire it all together

public static void main(String argv) {
    Light light = new Light();
    Switch switch = new Switch(light);

    System.out.println("Light is on: " + light.isOn());
    switch.clickOn();
    System.out.println("Light is on: " + light.isOn());
    switch.clickOff();
    System.out.println("Light is on: " + light.isOn());
}

这更面向对象,不需要任何全局变量。

有两种方法

更具体的方法

观察者方法

这可能非常适合于更一般的东西,它实际上扩展了我之前给出的示例。如果您不熟悉它,这是一种实现事件的方法,从而在两个对象的状态之间建立联系,而当一个对象发生更改时,另一个对象会观察到这些更改并做出相应的反应。在这种情况下,您的灯光会观察开关。

如果您想在灯光开关和灯光之间解除耦合,请检查我的解决方案。您可以轻松添加/删除灯光和开关之间的链接

private Light current;
public LightSwitch(Light light) {
  this.current = light;
  on();
}
public boolean isOn() {
  return current.isOn();
}
public void on() {
  current.setOn(true);
}
public void off() {
  current.setOn(false);
}
public String toString() {
  return isOn() ? "switched on" : "switched off";
}
轻量级:

照明开关等级:

SwitchListener类:

使用示例:


听起来经典的观察者设计模式适合这里。你认为我是什么
ean全局变量?你是说静态变量吗?@LocHa是的,类似于公共静态…@Arkadity谢谢你的回答你做了什么我在OOP课上也学到了,但我只是觉得光怎么能生活在毫无意义的开关中。这个案例研究我只关注两个完全独立的类,但它们可以彼此共享变量。问题是如何解决?@terces907:我的解决方案将解决您的问题:灯和开关完全独立。灯不在开关中。开关能感知光线。开关必须切换某些东西,对吗?实际上,你需要一个可切换的接口。这些术语不是我们在这里所拥有的,而是我们在这里所拥有的。让我们来讨论一下现实世界。创建开关时,此开关是否需要准确了解灯光目标?答案是否定的。所以公共开关灯的目标不是很好的设计。当然可以。如果你想让它更逼真,可以引入可切换的电流载体和电线。
public class Light {

    private boolean on;

    public void setOn(boolean on) {
        this.on = on;
    }

    public boolean isOn() {
        return on;
    }
}
public class LightSwitch {

    private boolean on;

    private Map<String, SwitchListener> listeners = new HashMap<String, SwitchListener>();

    public void switchState() {
        on = !on;
        SwitchEvent event = new SwitchEvent(on);

        for (SwitchListener switchListener : listeners.values()) {
            switchListener.switchPerformed(event);
        }
    }

    public void addListener(String id, SwitchListener listener) {
        listeners.put(id, listener);
    }

    public void removeListener(String id) {
        listeners.remove(id);
    }
}
public class SwitchEvent {

    private boolean on;

    public SwitchEvent(boolean on) {
        this.on = on;
    }

    public boolean isOn() {
        return on;
    }
}
public interface SwitchListener {

    void switchPerformed(SwitchEvent event);
}
    public static void main(String[] args) {

        LightSwitch lightSwitch = new LightSwitch();

        final Light light1 = new Light();
        final Light light2 = new Light();

        lightSwitch.addListener("light1", new SwitchListener() {

            @Override
            public void switchPerformed(SwitchEvent event) {
                light1.setOn(event.isOn());
            }
        });

        lightSwitch.addListener("light2", new SwitchListener() {

            @Override
            public void switchPerformed(SwitchEvent event) {

                // Example: light 1 on, light 2 off -- light 1 off, light 2 on
                light2.setOn(!event.isOn());
            }
        });

        // Test switch
        lightSwitch.switchState(); // light 1 ON, light 2 OFF

        lightSwitch.switchState(); // light 1 OFF, light 2 ON
    }