Java中如何让BookshelfService持有并操作创建的Bookshelf实例(不允许传递该实例作为参数)
嘿,别慌!你遇到的其实是Java面向接口编程里对象封装与生命周期绑定的典型问题,我来帮你捋清楚怎么解决~
首先,你之前的create方法有两个关键问题:
- 你直接
new BookshelfService()——但BookshelfService是接口啊,不能直接实例化,得new它的实现类BookshelfServiceImpl - 你创建的
myBookshelf没有和Service实例绑定,方法执行完就失去引用被GC回收了,自然后续方法访问不到
核心思路:让BookshelfServiceImpl持有Bookshelf实例作为成员变量
因为接口不能有成员变量,但它的实现类可以!我们把Bookshelf的引用存在实现类的私有成员里,这样所有Service的方法都能直接操作这个实例,同时外部代码完全看不到这个Bookshelf,完美符合“只能通过Service接口操作”的要求。
第一步:修改你的create方法
把创建的Bookshelf传给BookshelfServiceImpl的构造器,让实现类绑定这个实例:
public BookshelfService create() { // 1. 创建实际的Bookshelf实例 Bookshelf myBookshelf = new Bookshelf(); // 2. 把Bookshelf传给Service实现类的构造器,完成绑定 BookshelfServiceImpl serviceImpl = new BookshelfServiceImpl(myBookshelf); // 3. 返回接口类型(遵循面向接口编程的要求) return serviceImpl; }
第二步:改造BookshelfServiceImpl实现类
给它加一个私有成员变量保存Bookshelf,然后在构造器里初始化,这样所有Service方法都能访问这个实例:
public class BookshelfServiceImpl implements BookshelfService { // 私有成员:持有当前要操作的Bookshelf实例,外部完全不可见 private Bookshelf myBookshelf; // 构造器:传入要绑定的Bookshelf实例 public BookshelfServiceImpl(Bookshelf bookshelf) { this.myBookshelf = bookshelf; } // 现在实现addAuthor方法就能直接操作绑定的Bookshelf了 @Override public void addAuthor(String name, String email, String id) { Author newAuthor = new Author(name, email, id); // 调用Bookshelf的对应方法添加作者(这里假设你有addAuthor方法,替换成你实际的方法名) myBookshelf.addAuthor(newAuthor); } // 其他Service方法(比如addBook、removeAuthor、saveToXml等)都可以用这个myBookshelf成员变量操作 @Override public void addBook(String title, String authorId) { // 示例:添加书籍的逻辑,同样操作myBookshelf Book newBook = new Book(title, authorId); myBookshelf.addBook(newBook); } }
第三步:结合MainService的场景
不管是创建新书架还是加载现有书架,都是把得到的Bookshelf实例传给BookshelfServiceImpl的构造器,然后把Service实例存在MainService的成员变量里,这样用户后续操作菜单时,就用这个Service实例执行命令:
public class MainServiceImpl implements MainService { // 保存当前活跃的BookshelfService实例 private BookshelfService currentService; @Override public BookshelfService createNewBookshelf() { Bookshelf newBookshelf = new Bookshelf(); currentService = new BookshelfServiceImpl(newBookshelf); return currentService; } @Override public BookshelfService loadExistingBookshelf(String filePath) { // 从XML反序列化得到Bookshelf的逻辑 Bookshelf loadedBookshelf = unmarshalBookshelfFromXml(filePath); currentService = new BookshelfServiceImpl(loadedBookshelf); return currentService; } // 当用户选择书架操作时,直接用currentService调用对应的方法即可 public void handleAddAuthor(String name, String email, String id) { if (currentService != null) { currentService.addAuthor(name, email, id); } else { System.out.println("请先创建或加载书架!"); } } }
为什么这能解决你的问题?
当你从create或load方法返回BookshelfServiceImpl实例时,它内部已经持有了Bookshelf的引用。只要这个Service实例还被程序持有(比如存在MainService的currentService变量里),对应的Bookshelf就不会被回收,所有后续调用Service的方法都会操作同一个Bookshelf实例。
另外你提到“不能把Bookshelf作为参数传给BookshelfService”——其实这里的要求应该是不能让外部代码直接拿到Bookshelf实例,而Service实现类内部持有是完全合规的,因为外部只能通过Service接口的方法操作,完全看不到内部的Bookshelf,这正是接口封装的核心目的呀!
备注:内容来源于stack exchange,提问作者BlackSquirrelAJP

