是否可以在对象之间共享私有实例?

时间:2009-11-03 23:32:30

标签: java private-members

我只允许在我正在参加的编程课程中使用私人成员,我想知道这样的事情是否正常。

public class View {
    private Model object_;
    public View(Model object) {
       object_ = object;
       //blah blah blah
    }
//blah blah blah
}

public class Controller {
    private Model object_;
    public Controller(Model object) {
       object_ = object;
       //blah blah blah
    }
//blah blah blah
}

public class MainClass {
    public static void main(String [ ] args) {
        Model m = new Model();
        Controller c = new Controller(m);
        View v = new View(m);
        //blah blah blah
    }
}

View和Controller类都将模型的同一实例保存为私有字段。这可以接受吗?这似乎违反了私人领域的概念。我试着问我的教授,他说没关系,但我不确定他是否理解我的问题,或者我是否理解他的答案:)

7 个答案:

答案 0 :(得分:2)

关于标题问题:是的,没关系。想象一下树,兄弟姐妹共享对父母的引用。这种情况很常见。

答案 1 :(得分:1)

如果你看一下this article,你会发现理想情况下控制器位于模型和视图之间。所以我会或许重新组织你的依赖关系(对此有一些不同意见 - 见下文)

但是您的问题(无论域名)的答案是您可以分享这些私人参考。理想情况下,它们应该是 interfaces 的引用,并且实现可以在不更改依赖类的情况下进行更改。因此(例如)您将拥有Model接口和实现ModelImpl,并且共享引用的类型为Model。然后,您可以在以后替换不同的实现,而不会影响大部分代码。

答案 2 :(得分:1)

简短的回答是它很好。

更长的答案(忘记MVC一秒钟,因为看起来MVC是这样做的一个例子,而不是问题的核心)是你必须考虑可变性。如果一个对象不可变(对象上没有任何字段可以改变),那么共享是一件非常好的事情,它可以减少内存占用并且没有真正的缺点。

但是,如果对象是可变的,那么您必须了解更改对象状态如何影响对象的状态。在MVC中,很常见的是看到模型发生了变化,然后最终根据它调整了视图,因此您可以将其构建到设计中,但请考虑这种情况:

  private Collection myCollection; 

  public void setMyCollection(Collection someCollection) { 
       myCollection = someCollection; 
  }

这样的代码必须非常有信心,调用者不会将一个可变集合传递给它,之后会发生变化,或者它必须允许这样做。在上述情况下解决问题的典型方法是制作副本(myCollection = new ArrayList(someCollection);

总而言之,这是一种常见的做法,但是当对象是可变的时,你必须考虑对你设计的影响。

答案 3 :(得分:1)

简短回答: 两个具有引用同一事物的私有成员变量的不同类没有任何问题。这很常见。

长答案: 我的猜测是你的教授在这里谈论的是:
private Model object_是一个对象引用变量(不是基元)。因此,当您将object_传递给Controller和View的构造函数时,您将“链接”传递给相同的实例 object_,而不是传递 object_副本。

您是否选择将它们存储为Controller和View中的私有是完全不同的决定。我熟悉大学编程课程,禁止使用非私有成员变量(已经存在)。他们想要引入一些面向对象的概念,比如封装(后面),然后他们会告诉你为私有成员变量创建公共访问器和mutators。这通常是一个很好的原则,因为受保护和公共成员变量只应在您有充分理由的时候使用。

所以,是的,这些是正确的Java,但这是否真的是你想要对你的代码做什么是另一回事(参见Caleb的回答)。

答案 4 :(得分:1)

  

这可以接受吗?

是的。

  

好像它会违反私有字段的概念

没有。控制器无法从视图中更改实例,因为它是私有的。

考虑以下代码行,尝试在视图中更改模型:

public class Controller {
    private Model object_;
    public Controller(Model object) {
        object_ = object;
        this.object_.view.object_ = new Model(); // doesn't work.
        // or view.object_ = ....            
       //blah blah blah
    }
    //blah blah blah
}

这不行,1 st 因为,模型没有对视图的引用,而2 nd ,如果有的话, controller无法更改视图中的model,因为它对他来说是不可见的。

在某些情况下,可能不希望共享同一个对象。例如,如果您依赖于给定对象的状态并且该状态由其他对象更改,则您的代码可能会失败。请参阅Defensive Copying这就是为什么建议使用不可变对象并限制对它的访问。

但特别是在MVC设计模式中共享一个正是你需要的对象,或者至少共享该对象的状态。在MVC中,您需要的是ViewController以了解Model状态。看到同一个对象并不会使它们变得不那么私密(从某种意义上说,每个对象都不知道它们看到的是同一个东西)这允许Low Coupling

什么肯定会破坏对象隐私将该属性作为非私有属性:

class View {
   public Model m; 
}
class Controller {
    public Model m;  
}
....
public static void main( String ... args ) { 
     Model m = ... 
     View v = new View();
     Controller c = new Controller();
     v.m = m;
     c.m = m;
}

因为没有任何访问控制可以阻止发生疯狂的更改。

答案 5 :(得分:0)

据我所知,没有硬性和快速的“私人领域法则”,即一个对象可以由多个班级私下进行。对于类似于不可变引用类的东西,有意义的是多个类实例可以接收不可变引用类并将其保存为私有属性。

在您的示例中,Carl是正确的 - 视图和控制器通常应该将模型作为某个方法中的参数,而不是保留对它们的引用。所以代码看起来更像是这样:

public Response handleRequest(Request request) {
    Controller c = new Controller();
    Model m = c.processRequest(request);
    View v = new View();
    Response response = v.createResponse(model);
    return response;
}

答案 6 :(得分:0)

是的,这是可以接受的,如果需要,可以通过getter / setter方法控制对这些字段的访问来使用私有字段来强制执行封装。如果这些字段在public或甚至包之外的类可能会开始依赖于您的类的实现,这会使您在重构方法等方面受到限制。允许其他类访问他们应该访问的字段可以提供隐私泄漏。

如果模特在哪里公开。

Class messUp {

模型aModel = object_; aModel.doWhatTheHellIWantToYourModel();

}

这可以完全取消您系统的状态。