问题描述
我在ES2015中写这个,但是这个问题也可以用其他语言解决。
在我的情况下,我有一个像这样的Chat
类:
// Chat.js
import { socket, config } from "./Util.js";
import User from "./User.js";
class Chat {
constructor(socket, config) {
// …
}
roomExists(room) {
// …
}
createRoom(room) {
// …
}
}
// Make sure to export the same instance to every other module,
// as we only need one chat (resembling a singleton pattern)
export default new Chat(socket, config);
现在,此类在createRoom()
某个地方使用了User
。
问题在于User
类需要利用我们导出的Chat
实例:
// User.js
import chat from "./Chat.js";
export default class User {
join(room) {
if (chat.roomExists(room)) {
// …
}
}
}
但是现在我们在Chat.js
和User.js
之间有了一个依赖循环。
该脚本将无法运行。
解决此问题的一种方法是永远Chat.js
直接导入Chat.js
,而是执行以下操作:
// Chat.js
import { socket, config } from "./Util.js";
import User from "./User.js";
class Chat {
constructor(socket, config) {
// Pass `this` as a reference so that we can use
// this chat instance from within each user
this.userReference = new User(this);
}
roomExists(room) {
}
createRoom(room) {
}
}
// No need to export a singleton anymore, as we pass the
// reference to the chat in the User constructor
但是现在,所有其他类都依赖于Chat
并且一旦实例化它 , 就必须给它提供对聊天实例的引用 。
这也不干净,不是吗?
Chat
现在是单点故障,以后很难交换。
有没有更清洁的方式来管理这个?
1楼
MikeSW
1
已采纳
2015-07-26 20:05:32
更新
显然, User
不应该进行Chat
。
因此,聊天应如下所示
class Chat{
//other declarations
addUser(user,room) {}
createSpecificRoom(user,name){}
moveUserToRoom(user,newRoom) {}
}
如果要从用户对象执行操作,则可以使用双重调度。
class User{
joinChat(chat,room){
chat.addUser(this,room);
}
}
var chat=new Chat();
var user= new User();
user.joinChat(chat,room);
但是,IMO最好的办法是仅使用Chat
来添加/删除用户。
从语义上讲,它是跟踪房间和用户的工作。
关于单例,好吧,如果您使用的是支持DI的框架,那么几乎任何服务都是单例的,但您不必在意。
只要在您需要的任何地方插入Chat
。