OOP: calling a public method within the same class

I read an article about car collision avoidance systems when my programmer wise guy made me think of this concept in an object-oriented way, and it made me wonder if these systems respect the object-oriented programming model.

As the main developer of Java, I transferred this problem to the Java environment and raised a specific question: does calling a public method inside a single class (in a non-statistical context) respect and follow object-oriented?

I mean, take this short hypothetical Car class:

public class Car { // Class attributes. // Constructors. public void accelerate(final double amplitude) { // Accelerate according to the amplitude. } public void brake(final double amplitude) { // Brake according to the amplitude. } // Other useful methods. private void collisionPreventionActions() { // Some actions. brake(100.0); // Some other actions. } } 

Suppose a thread is responsible for detecting a collision and takes action when it detects a collision, and one of these actions will slow down. Obviously, the brake(...) method is becoming an interesting choice, but doesn't that violate the object-oriented way of doing things? However, this is not only brakes. What if the collision avoidance system in this class used the steering wheel instead to avoid an accident? It seemed strange to me that the car would use its own entrance from an internal point of view ...

More generally, suppose you have a common object that I like to see as a black box. Public methods will be equivalent to leverage on this black box that will control its behavior. Calling a public method in this object would mean that the black box activates its own leverage from its internal mechanism.

I ask because I know that it is legal in Java to do this, and that I have seen public methods that are called in the same class several times in my life, but this legal information does not necessarily mean that this is the right OO way to do this is.

Are public methods used in the same class in an unsteady context, following the rules of object-oriented programming and encapsulation? If not, what would be the right way to do this, or what could be a workaround?

+5
source share
6 answers

There is nothing wrong with this choice from the point of view of OOP: this is perfect for a method of performing actions that require a combination of other methods.

In practice, however, a general approach would be to divide the functionality into public and private parts, for example:

 public void brake(final double amplitude) { // check preconditions if (speed == 0) throw new IllegalStateException("cannot brake when standing"); if (amplitude <= 0) throw new IllegalArgumentException("amplitude must be positive"); // ... do other important checks doBrake(amplitude); } private void doBrake(final double amplitude) { // The real code goes here } 

Now your collisionPreventionActions can call doBrake instead of brake , assuming that you have checked all the necessary prerequisites before making the call.

Note: doBrake must also verify its prerequisites. However, instead of throwing exceptions when the preconditions are not met, he can use statements. The difference is that exceptions indicate the misuse of your public methods by others, while statements indicate the misuse of your encapsulated methods by you or someone else supporting your code.

+6
source

No rules are violated when an object uses its own API. On the contrary, problems can occur if a class has an API that can be overridden, but it cannot use this API internally.

As a trivial example, consider a non-final accessory of properties. An object can skip an accessory and read (or, worse, write) fields directly. Suppose the accessor is overridden in a subclass to calculate the value of the property using the field along with some other information from the subclass. Now the class is broken because it did not fulfill its own contract.

Consider the (somewhat contrived) Point and OffsetPoint below. The OffsetPoint class is OffsetPoint correctly, but the inherited toString() method will not work as expected because the parent class Point does not mistakenly use its own accessors.

 public class Point { private final int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } @Override public final String toString() { /* Here the bug; should be getX() and getY() instead of x and y */ return String.format("(%d,%d)", x, y); } } class OffsetPoint extends Point { private int dx, dy; OffsetPoint(Point point, int dx, int dy) { super(point.getX(), point.getY()); this.dx = dx; this.dy = dy; } @Override public int getX() { return super.getX() + dx; } @Override public int getY() { return super.getY() + dy; } } 
+3
source

Does publicly use methods in the same class use the rules of object-oriented programming and encapsulation in a non-stationary context?

No, there is no problem with encapsulation, because the method is publicly available, so anyone (even this ) can call it.

However, for something like a collision avoidance system, relying on publicly available methods can be poor security.

Let me use your example of this internal collision sensor calling the open brake() method. What if someone subclassed the car and redefined the method?

 public class BrokenCar extends Car{ @Override public void brake(final double amplitude) { //BREAKS CUT!!! } } 

Thus, there are some security rules that do not rely on overriding methods. Creating the final brake and accelerate methods fixes this problem.

+1
source

Yes, I think that in the context of OO it is correct to use your own public method. This is quite often when there are overloads for a method that all but one call the most specific, either filling in the default values ​​for missing parameters, or changing the type of arguments. I also see a template in which all overloads are called in a private or protected method with the same name with the addition of _internal or _impl at the end. For example, multiple ComputeSpeed ​​overloads may cause a call to ComputerSpeed_internal. This template would be appropriate if in the public methods that you do not want to do twice, or are not suitable for internal calls, parameter validation exists.

You can, of course, introduce problems without having a clear separation of problems. For example, if the caller of the collisionPreventionActions element also decided that it would be nice to set the brake, you might be faced with how much the brake is applied.

KC

0
source

In general, it’s ok to publish methods. The fact is that it should be the car interface. In this case, preventCollision() belongs to the Car class or in some other CollisionPrevention class.

Interrupting your code with several classes with a single responsibility , and then using a larger class like Car , is usually a good idea.

0
source

I completely agree with you that the class itself refers to its private members and methods. But I do not understand why this should not be legal from the point of view of an object-oriented paradigm. Consider the following example:

 public class Human { public Human() { liveYourLife(); } private void liveYourLife() { while(alive){ createYourDay(); } } private void createYourDay() { drink(); eat(); sleep(); awake(); drink(); } private void eat() {} private void drink() {} private void sleep() {} private void awake() {} } 

Perhaps someone will criticize the simple rule of life shown in the example above. But what I want to demonstrate with the help of a few lines above is that "usually" a person is allowed to define his daily life.

The basic principle of OO-Paradigm is to describe the actions and properties of real-world objects. Therefore, as long as you are allowed to decide for yourself when you want to eat, drink, sleep, etc., your model described above is absolutely correct. But if you find some exceptional cases in your problem area that you want to address in your software (for example, you are arrested, etc.), you must update your OO design.

If there is something that greatly affects the state of another instance, you should consider this “violation instance” as another object that refers to the actual instance.

 public class Prisoner extends Human { @Override private void liveYourLife() { while(jailed){ createYourDay(); } } @Override private void createYourDay() { // A bit different :) } } public class Prison { private List<Prisoner> prisoners; } 
0
source

Source: https://habr.com/ru/post/1202362/


All Articles