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
已经发生了
我可以通过引入publicport.add
和line.add
,来恢复对称性,这将调用API privateline.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);
}
}