1

Let's say I have an class to model a city. Its characteristics are the following:

  • It has only two properties "name" and "population", both private, that are set in the constructor.
  • It has getters for these properties, but not setters.

I don't want any user of this class to set the properties, I want them to use a public .edit() method.

This method needs opens up a form to input the new name of the city and population, i.e.: a view. Then, if I have a view, I would like to implement the MVC pattern, so the idea would be that the controller receives the .edit() call, renders the view, retrieves the data back, and sends it to the view so that it changes its state.

But, if I do so, I have to change the properties of the city model from private to public. So, if any user instantiates my class, she/he can directly change the properties.

So, the philosophical question: Isn't that breaking the encapsulation?

EDIT Just to make it more explicit:

This city_instance.edit() method should be the only way to mutate the object.

Besides, I see that part of my problems comes from the misunderstanding that a model is an object (you can read that on php mvc frameworks), when it is actually a different abstraction, it's a layer that groups the business logic (domain objects + I guess more things)

2

2 Answers 2

3

Disclaimer: I don't really understand where are you proposing the .edit() method to be implemented, so it would help if you could clarify that a little bit there.

The first thing to consider here is that in the bulleted list of your question you seem to imply that a City instance acts like an immutable object: it takes its instance variables in the constructor and doesn't allow anybody in the outside to change them. However, you later state that you actually want to create a way to visually edit a City instance. This two requirements are clearly going to create some tension, since they are kind of opposites.

If you go the MVC approach, by separating the view from the model you have two main choices:

  • Treat your City objects as immutable and, instead of editing an instance when the values are changed in the form, throw away the original object and create a new one.
  • Provide a way to mutate an existing City instance.

The first approach keeps your model intact if you actually consider a City as an immutable object. For the second one there are many different ways to go:

  • The most standard way is to provide, in the City class, a mutator. This can have the shape of independent setters for each property or a common message (I think this is the .edit() method you mentioned) to alter many properties at once by taking an array. Note that here you don't take a form object as a parameter, since models should not be aware of the views. If you want your view to take note of internal changes in the model, you use the Observer pattern.
  • Use "friend" classes for controllers. Some languages allow for friend classes to access an object's internals. In this case you could create a controller that is a friend class of your model that can make the connection between the model and the view without having to add mutators to your model.
  • Use reflection to accomplish something similar to the friend classes.

The first of this three approaches is the only language agnostic choice. Whether that breaks encapsulation or not is kind of difficult to say, since the requirements themselves would be conflicting (It would basically mean wanting to have a model separated from the view that can be altered by the user but that doesn't allow the model itself to be changed for the outside). I would however agree that separating the model from the view promotes having an explicit mutation mechanism if you want mutable instances.

HTH

Sign up to request clarification or add additional context in comments.

2 Comments

My idea wasn't to make City immutable, but to allow changes only by calling its .edit() method. And this method should render a form (which return new property values) and assign these new values to the private properties. Not taking an array/values from outside. Nevertheless, part of my mess comes from the misguided idea that a model is an object, instead of a layer of business logics. Thanks for the useful answer.
@ikaros45 Ok, I see. In that case the problem is that you are actually breaking the MVC, since the domain object (the model) actually knows the view. The MVC lays out things in the opposite way (thew view knows the model and the model doesn't know anything about the view). This is nice, since you don't pollute your domain logic with view-driven code and you can have as many views as you want over the same object (e.g. both a desktop and a web view).
1

NOTE: I'm referring to MVC as it applies to Web applications. MVC can apply to many kinds of apps, and it's implemented in many kinds of ways, so it's really hard to say MVC does or does not do any specific thing unless you are talking strictly about something defined by the pattern, and not a particular implementation.

I think you have a very specific view of what "encapsulation" is, and that view does not agree with the textbook definition of encapsulation, nor does it agree with the common usage of it. There is no definition of "Encapsulation" I can find that requires that there be no setters. In fact, since Setters are in and of themselves methods that be used to "edit" the object, it's kind of a silly argument.

From the Wikipedia entry (note where it says "like getter and setter"):

In general, encapsulation is one of the four fundamentals of OOP (object-oriented programming). Encapsulation is to hide the variables or something inside a class, preventing unauthorized parties to use. So the public methods like getter and setter access it and the other classes call these methods for accessing.

http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)

Now, that's not to say that MVC doesn't break encapsulation, I'm just saying that your idea of what Encapsulation is is very specific and not particularly canonical.

Certainly, there are a number of problems that using Getters and Setters can cause, such as returning lists that you can then change directly outside of the object itself. You have to be careful (if you care) to keep your data hidden. You can also replace a collection with another collection, which is probably not what you intend.

The Law of Demeter is more relevant here than anything else.

But all of this is really just a red herring anyways. MVC is only about the GUI, and the GUI should be as simple as possible. It should have almost no logic in either the view or the controller. You should be using simple view models to deserialize your form data into a simple structure, which can the be used to apply to any business architecture you like (if you don't want setters, then create your business layer with objects that don't use setters and use mutattors.).

There is little need for complex architecture in the UI layer. The UI layer is more of a boundary and gateway that translates the flat form and command nature of HTTP to whatever business object model you choose. As such, it's not going to be purely OO at the UI level, because HTTP isn't.

This is called an Impedance Mismatch, which is often associated with ORM's, because Object models do not map easily to relational models. The same is true of HTTP to Business objects. You can think of MVC as a corollary to an ORM in that respect.

2 Comments

What I wanted to point is that the MVC pattern, (or let's be more specific since MVC is a confused term: the separation of concerns), entails that the objects must be mutable from outside, since the view (from where I want to retrieve the data) should not be contained within it. By the way, MVC is especially misunderstood in web development. What you are describing about views with no logic is closer to the PAC pattern. In real MVC is the view who pulls data from the model. Check this out garfieldtech.com/blog/mvc-vs-pac
@ikaros45 - I don't think you're doing a very good job of explaining your point. Of course MVC requires that objects be mutable from outside. How else would they be mutated? They can only be mutated by another object doing something to mutate it from outside.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.