Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/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_Oop - Fatal编程技术网

Java 面向对象循环引用

Java 面向对象循环引用,java,oop,Java,Oop,关于什么是循环引用,什么不是循环引用,我有一个两难的问题。。。在肯定的情况下,如何摆脱它 假设我有一个Main类,它实例化了两个不同的类,其中每个类都需要在另一个类中执行一个方法: MyMain { AlarmManager alarmManager; DatabaseManager databaseManager; MyMain() { alarmManager = new AlarmManager(dataBaseManager);

关于什么是循环引用,什么不是循环引用,我有一个两难的问题。。。在肯定的情况下,如何摆脱它

假设我有一个
Main
类,它实例化了两个不同的类,其中每个类都需要在另一个类中执行一个方法:

MyMain {
    AlarmManager alarmManager;
    DatabaseManager databaseManager;

    MyMain() {
        alarmManager = new AlarmManager(dataBaseManager);
        databaseManager = new DatabaseManager (alarmManager);
    }

    AlarmManager getAlarmManager() {
        return alarmManager;
    }

    DatabaseManager getDatabasetManager() {
        return databaseManager;
    }
}
课程包括:

AlarmManager {
    DatabaseManager dataBaseManager;

    onAlarm(alarm) {
        dataBaseManager.saveInHistorical(alarm);
        sendAlarm(alarm);
    }

    sendAlarm(alarm) {
        socketWriter(alarm);
    }
}

DatabaseManager{
    AlarmManager alarmManager;

    onDatabaseConnectionError() {
        saveInHistorical(databaseAlarm);
        alarmManager.sendAlarm(databaseAlarm);
    }

    saveInHistorical(historical) {
        connection.store(historical);
    }
}
我想你是看了代码才明白的。如果有报警,我们会在AlarmManager中接收,但需要将其保存在历史数据库中。但是,如果我们与历史数据库存在连接错误,我们还需要发送警报


这是否真的是一个循环引用,其中main有报警,但报警也有main,对于数据库/main也是如此?你将如何解决它

我在进行CAD开发时遇到了类似的问题。在每个电子CAD中,都有一些组件端口和信号线,表示端口之间的连接。线路和端口是多对多连接:每条线路必须维护一个它绑定在一起的端口列表,并且端口必须注意连接到它们的线路。所以,每当用户想要连接两个端口时,他都会创建一条线,并通过

line.add(port)
port.add(line)
这两个操作必须始终同时执行。这意味着它们必须抽象为一个过程:调用
line.add(port)
将自动调用
port.add(line)
,并且,通过对称,
port.add(line)
应该调用
line.add(port)
。好吧,我们正处于恶性循环中,这正是你在问的问题

我困扰了我好几年,但我没有做比放弃对称更好的事。我只向用户公开了
line.add
,将它调用的
端口隐藏在我的网表操作API后面。这样,
port.add
就不需要调用
行。add
返回,因为我们知道我们在
端口。add
只是因为
line.add
已经发生了

我可以通过引入public
port.add
line.add
,来恢复对称性,这将调用API private
line.onAdd(port)
port.onAdd(line)
回调。这似乎也很琐碎。然而,你问这个问题是对的。我鼓励你对我的回答投赞成票,但不要接受。我想知道自己的正确答案。

试试这个:

MyMain() {
    alarmManager = new AlarmManager();
    databaseManager = new DatabaseManager();
    alarmManager.setDatabaseManager(databaseManager);
    databaseManager.setAlarmManager(alarmManager);
}
alarmManager类具有setDatabaseManager方法


databaseManager类有一个setAlarmManager方法。

Gilbert有一个很好的方法,但另一种方法是让alarmManager和databaseManager都引用
MyMain
。e、 g

  • 优点:不需要设置器,您的类可以是不可变的
  • 优点:简单实用
  • 缺点可能是一个优点:更大的耦合。将来,当您添加AlarmManager和DatabaseManager所需的FooManager和BarManager时,它们也可以在MyMain中,极大地简化您的生活。然而,这无疑增加了耦合性和“全局性”,因此过多的耦合将是一件坏事。如果你超越了“简单实用”而变成了“这是厨房水槽”,你应该停下来重新思考
  • 缺点是我不在乎,因为我认为这是一个糟糕的法律:违反了德墨忒尔法。但是,如果你真的在意的话,它很容易被修改来避免这种情况

  • 这看起来像是一个设计缺陷,你能详细说明这些类,以及它们应该做什么吗?也许我们能想出一个不同的设计如何解决婚姻问题?我喜欢这个问题!我确信有很多(学术)解决方案,但我(务实)会为事件和警报设置一个基类。@BartlomiejLewandowski“设计缺陷”或大脑中的结,你说的“需要后退一步”是对的,我想我已经在答案中按解决方案发布了。自从我沉迷于这个问题已经有10多年了,但我仍然对解决这个古玩和看似不必要的问题感兴趣。我改变了密码。以前是事件管理器,现在为了更好地理解,我使用数据库管理器。我希望你现在明白了。问题是,我有许多所谓的“管理者”相互关联,我不知道如何将它们解耦以避免循环引用。
    AlarmManager {
        MyMain myMain;  // set in the constructor, could be final
    
        onAlarm(alarm) {
            myMain.getDataBaseManager().saveInHistorical(alarm);
            sendAlarm(alarm);
        }
    
        sendAlarm(alarm) {
            socketWriter(alarm);
        }
    }
    
    DatabaseManager{
        MyMain myMain;  // set in the constructor, could be final
    
        onDatabaseConnectionError() {
            saveInHistorical(databaseAlarm);
            myMain.getAlarmManager().sendAlarm(databaseAlarm);
        }
    
        saveInHistorical(historical) {
            connection.store(historical);
        }
    }