So i'm preparing for an exam and trying to figure this one out, whether it breaks encapsulation or not. No idea if with question even makes sense, but I'm working on a game that has a bunch of server classes and a client class Game.
In my Player class I have this field
private Room currentRoom;
and a accessor method:
public void getCurrentRoom {
return currentRoom;
}
Room class has:
private String Name;
private ArrayList<Item> items;
private HashMap<String, Room> exists;
I've used the get method seven different places in the Game class, but I don't know if it breaks the principle of encapsulation by returning it directly - if it does, what would a better approach be?
Thank you.
First off, this code won't compile, since it needs to return an instance of type Room
public void getCurrentRoom {
return currentRoom;
}
Does it break the principle of encapsulation?
No.
Principle of Encapsulation:
Encapsulation helps to create code that is loosely coupled. Because
the details are hidden, it reduces the ability of other objects to
directly modify an object's state and behavior.
Since your getter callers wouldn't know how the current room was set,
it has hidden its implementation behind the scenes.
Your function to set the current room needs to be private in order
to hide the implementation
Source:
https://gamedevelopment.tutsplus.com/tutorials/quick-tip-the-oop-principle-of-encapsulation--gamedev-2187
Related
I am working on some practice questions for the OCP 8.
One question featured a class with private fields and private getter methods. The correct answer was that this code violates encapsulation because the getter methods should have been public.
public class A {
private String a;
private String getA() { return a; }
}
However, another question featured a class with private fields and no getter methods at all. The correct answer was that this code follows encapsulation principles.
public class A {
private String a;
}
Assuming all data fields are private, shouldn't the order of most encapsulated to least be no getter methods, private getter methods and public getter methods?
I know my question might sound opinion-based, but the exam is not.
Private getter methods do not violate encapsulation. That is just nonsense.
I am not expressing an opinion here. It is a fact that a Java private method can only be called within the class that declares it. That is inside the boundary of encapsulation.
Either you have misread the OCP sample question and answer, or they have made a mistake.
Now it could be that what they were trying to ask was whether the example class was an example of good encapsulation or more generally of good OO design.
UPDATE
Seeing the example code, it is hard to say one way or another. It is too unrealistic to make a judgement. (The code is literally useless, but unless we know what its intended use was, we can't really call this bad design.)
Another answer seems to be arguing that private getters are useless. I disagree. Especially since a getter may do other things apart from simply returning a value. Consider this:
private synchronized void setBalance(int newBalance) {
this.balance = newBalance;
}
private synchronized int getBalance() {
return this.balance;
}
This ensures that the caller will see the current value of the balance field even if it was just updated by another thread. Sure we can do it other ways, but this way is good separation of responsibilities.
And there other that a private getter could legitimately do.
Because, if you make a getter as private, then there is no way to access that data member in another class. We use a getter to access the private data member in another class. So if you are making getter as private, then what is the use of that getter.
As much as I have studied about encapsulation it is about hiding data to prevent from manipulation. For that we declare the private variables so that couldn't be accessible from out of class. But we can implement or access them out of class using setter getter method. So if we have to implement it using setter getter method than any other person can implement it using setter getter method. . So how we are safe from manipulation??
Encapsulation isn't a security measure in that it prevents people from messing with your code. It's a security measure in the sense that people can't go directly in and change variables without going through your proper channels. Consider the following psuedocode.
class ProgressBar {
public int maximum;
public int current;
}
vs
class ProgressBar {
private int maximum;
private int current;
...
public set_current(int amount) {
if (amount <= this.maximum) this.current = amount;
}
}
In the top example, users could go in and mess with current and break the
progress bar. In the bottom example, your setter protects from that.
You need to look at this way,
your code <------ client code
Client code will be trying to access your code. With Encapsulation, your data will be safe from manipulation that can be done by the client code. It will help in specifying the accessibility limit.
To give an Example,
You are building a game and you wouldn't want someone to increase the health of your character (manipulate the fixed data)
public class GameCharacter {
public int Health{ get; }
public GameCharacter ()
{
Health = 100;
}
}
No one can change the Health!
The purpose of Encapsulation is two-fold:
Bundling related functionality together;
Controlling the access to fields and methods which participate in providing the functionality.
The goal of getters and setters is to ensure that actors outside the code (or class) have only one point of interaction with your fields, thus maintaining the invariants. This helps in:
Preventing modification of values in an illegal/unacceptable manner that can break the functionality.
Ex: Two external actors trying to modify your account balance at the same time;
Localizing an aspect of code that may change in future.
Ex: Easily allowing you to change the type of a status variable from boolean to enum in future because it is always accessed from getter in the class;
Implement business rules, if any, that are need to be exercised when changes are made to your fields.
Ex: Not allowing the Engine class to modify and set the speed of your Car class to a negative value, just because the car is going in reverse.
We can access Private data members using accessor method such as
private int num=5;
public int get_num()
{
return num;
}
and we can access the returned value from any class even though num is private data member.
So on Similar note cant we create accessor method that returns private methods?
I just had a thought about it,If we cannot do this please explain.Thank You
Private methods are created when refactoring your code. They are implementation details, which nobody outside needs to know. They are used inside public methods, which are supposed to provide the functionality you want to provide to your client(each public method can be called an API which is used/consumed by other classes i.e. its clients).
Access modifiers are provided to help you achieve proper abstraction. So anything marked private is directly accessible only inside your class. But if you want someone outside to read/write its value, you expose it via getters/setters. Similarly private methods are not accessible outside the class. But nobody is stopping you from creating public method that only calls this private method. This way you do achieve access to private method. But it would be a very poor design.
You can access private method via public method. This is sometimes used to wrap complicated private method and expose simpler, public API.
class Delegator {
private void doPrivateStuff(int param) { ... }
public void doStuffOnce() {
doPrivateStuff(1);
}
public void doStuffIfConditionIsMet() {
if(condition) {
doPrivateStuff(1);
}
}
}
You can also access private methods using reflection.
http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html
Because the accessor is public, it can be accessed from outside the class; even if it returns private data.
The access modifier of the returned data isn't relevant, only the access modifier of the method matters.
If you created a public method that returned a reference to a private method, yes, you could then call the private method from outside the class. That would entirely defeat the purpose of making the method private however.
You my be wondering "why make a public getter to a private variable". The answer is that although it's possible to retrieve the private data, it isn't possible (unless you create a public setter as well) to change the public data. This assumes that the private days is immutable. If it's mutable, retuning a reference to private data negates any protection you get from making the variable private.
TL;DR
Accessing private methods violates the basic object oriented principle of encapsulation. The question is not "can we access a private method?" but "should we ever do it?". It contradicts the principle of information hiding and it breaks the contract an object "offers" to its consumers. Objects or classes that enforce you to do that should be considered poorly designed.
Why you shouldn't access private members
First a classes should implement a part of your domain logic that is so closely related that there are little interactions necessary with the outside world to fulfill its duties (this is called high cohesion). You then define a public interface for your class / object with functionality that you expose to the outside world - consumers of your object must only use this interface (this is called loose coupling).
Private methods can be seen as a way to structure your code inside your class in a better readable way - they are not intended to be shared with the outside world. Consider them as a "safe space" for the developer of the class to make arbitrary changes without breaking the contract. That's the reason why there can be bad side effects if you actually access private methods: your code is likely to break it the developer of the class decides to change the implementation of such a method. Effective Java, Chapter 4, Item 13 explains this for protected members:
For members of public classes, a huge increase in accessibility occurs when the access level goes from package-private to protected. A protected member is part of the class's exported API and must be supported forever. Also, a protected member of an exported class represents a public commitment to an implementation detail.
Exceptions
The only exception I know from the rule of "not accessing private members outside of an object" is in testing, when you either want to reset a certain variable (e.g. a Singleton) or you want to facilitate the testing of complex logic by testing the private parts of the implementation and hence reducing complexity in testing.
Java has a protected mode for the members of its classes that allow sub-classes access to them. I read somewhere that there are issues with this. The only issue I can think of is that a programmer might forget the protected members are part of the API and cannot be change arbitrarily. Are there other issues?
Of the four member access levels, private and default (package-private) are concordant with encapsulation, i.e. members that are hidden preserve the autonomy of your implementation details. In other words, the less that the users of your API know about your class implementation details, the less you are tied to that implementation and the freer you are to change it at any time without breaking the contracts your API users have relied upon.
As soon as you go up to protected access (and public access) then you are bound to that implementation and must continue to support it until your API's life ends (or you go out of business). Accessible members tend to tie you to a particular implementation, even if you'd like to change it, so ... lots of accessible members are not concordant with tight encapsulation.
But more than that, access also exports risk. The more aspects of your class that are exported by your API, then there are more potential exploits that malicious users can try and hack.
Protected access, for example, can be used to override methods in your class that you had forgotten to make final. This can break your API and, worse, enable malicious users to access instance data that you did not intend to allow.
First, I'm not seeing that a protected member of any class could be considered part of a public API, given that a protected field or function is not visible to the world.
Ultimately, when writing an API, the idea is to have the interface, or contract, be as unchanging as possible; how it's done can change with each revision (although hopefully, not too much).
One issue I could potentially see with protected members in classes would be overriding their behavior to produce radically divergent behavior from the parent, while satisfying the generic contract of the API (that is, if I'm expecting a numerical value, I get it back; if I'm expecting a boolean, I get it back. The correctness of the value/boolean is suspect, though, and should be tested).
Example: Suppose I have a class Parent and a class Child. Both implement an interface called Teachable. This allows them to learn a particular Subject, which is a simple enumeration construct. The contract for Teachable is given as:
public interface Teachable {
/**
* Learn a particular subject.
* This requires that the element being learned hasn't previously been learned.
* #param thisSubject the subject to be learned
* #return whether or not the subject learned was unique.
*/
public boolean hasLearned(Subject thisSubject);
}
Suppose now we have our implementation of the Parent and Child classes as follows:
public class Parent implements Teachable {
private Set<Subject> subjectsLearned = new HashSet<>();
#Override
public boolean hasLearned(final Subject thisSubject) {
return learn(thisSubject);
}
protected boolean learn(final Subject theSubject) {
return subjectsLearned.add(theSubject);
}
}
class Child extends Parent {
private Set<Subject> subjectsLearned = new HashSet<>();
#Override
public boolean hasLearned(final Subject thisSubject) {
return learn(thisSubject);
}
#Override
protected boolean learn(final Subject theSubject) {
return !subjectsLearned.add(theSubject);
}
}
I've effectively changed the behavior of the class which is said to adhere to the behavior of my API, because I could override it. The first time a Child learns a particular Subject, they'll claim they already know it. Only the second and subsequent times would they not.
I have a singleton class containing a bunch of control data that needs to be kept synchronized with the rest of my application. As a result, there are many times which I want another class to be able to read the information but not modify it. Currently, this singleton class has many public variables. I don't want to use getter and setter functions because they are wordy and annoying. Also, there are a lot of variables.
If my singleton class is called ControlData, I could create a second create a second class called ImmutableControlData, where it has all the same members, but they are declared final. Then, when retrieving my singleton, I would return an ImmutableControlData, rather than a ControlData object. However, this means that I need to constantly maintain the ImmutableControlData class as well as the ControlData class (annoying...)
If I had const-pointers, I would just return a const-pointer to my ControlData object. What can I do in Java, instead?
Java does not have const correctness like C++.
You could make an interface that declares the methods to read the data, but not the methods to modify the data. Make the class that holds the data implement this interface. Methods elsewhere in your program that should only read the data, should accept the interface, not the class, as the parameter type. For example:
public interface ReadablePerson {
String getName();
}
public class Person implements ReadablePerson {
private String name;
#Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// Elsewhere...
public void someMethod(ReadablePerson p) {
System.out.println(p.getName());
}
Ofcourse, in someMethod you could still subvert this by casting p to Person, but at least it requires some conscious effort (adding the cast), which should alert the programmer that (s)he is doing something (s)he shouldn't do.
An advantage of this solution is that you don't have to make a defensive copy of the data.
First: If your Class has so many members, you should try to split the class into littler ones. Maybe you can summerize some variables eg.
ControlflowVariables
StateVariables
If you want to restrict the access to the variables you have to use getter. IDE can create getters and setters for you. The access to variables are the same:
singletonClass.variable is not worst then singletonClass.getVariable()
If you want to restrict the access only at some points in your code then create a final copy of tha variable
final int variable = singletonClass.getInstance().variable;
Personally, I would not try to control access in this way. There is nothing you can to do to prevent bad programmers from misusing your class. Even in C++, they could use a simple const_cast to remove your "protection" and modify the singleton any way they like.
Instead, I would restructure the code to make it easy for others to do the right thing and hard for them to get it wrong. Segregate the interface for ControlData into two separate interfaces: one for reading the object and one for updating it. Then simply provide the two interfaces where they're needed.