The Pain of OOP Lecture #2: Static methods and attributes [object oriented programming crash course]

preview_player
Показать описание
A lecture for BSc students in Innopolis University.

0:00 Lecture description
1:43 What static methods are for
7:18 Problems
11:43 Coupling
20:49 Eagerness
32:38 Cohesion
37:58 Attributes. Literals
53:14 Singletones
1:09:41 FastJson as Example
Рекомендации по теме
Комментарии
Автор

Thanks! I'm Brazilian and I follow your lectures. I learned a lot.

Laecios
Автор

A really interesting lecture!

The fun fact is that I already did all these design mistakes in my last project which is a git clone CLI using Java, and I was searching for a solution for testing the utility class, I am really happy I found how can I solve such issues.

Good content, just continue with the same rhythm😉😄👌

mohamedhanyy
Автор

This is so great that you are going through this series again

I have written a Java “applet” integrating your ideas and its working amazingly well, based on your jpages project

I wonder if you would want to see it. I’m primarily a Kotlin dev and Java is is not daily language.

ChrisAthanas
Автор

1:15:04 it’s for creating an object without having an instance of the class

This is all imperative code masquerading as OOP

The authors (like most) just designed it how it works in C++ which is just imperative C all dressed up to be more complicated than it needs to be

Typical COP ( Class Oriented Programming)

ChrisAthanas
Автор

Singleton is used to make a class static but still has all the features of OOPs like inheritance, overriding, overloading and etc

iamsinghankit
Автор

Everybody explaining OOP like this: Look there is a blueprint (class A) and you create object from the blueprint (new A()). BUT I always was struggling to understand the static things in that scenario. Thank a lot. I think i will kick of the "STATIC" from my codes in future at least i will try

farrukhjonnazriev
Автор

1:20:08 это класс-кластер, когда в зависимости от параметра или вызванного метода (обычно статического) возвращается какой-то «подкапотный» класс (часто приватный), соответствующий интерфейсу.

egormerkushev
Автор

1:04:03

If this database connection is present in each and every function (probably starting from the very top), a developer of the middle function can access it before passing to the next function.
Is it bad that almost everybody in this chain of function calls has an access to this object (anyone can close the connection before it even arrive to a dedicated function, for example)?

adamm
Автор

Do you have any thoughts about extension functions like kotlin has?
I see that in kotlin instead of Utils there is usually an Extensions file and it is kind the same thing, but those functions are linked with Classes defined elsewhere and called through the objects of those classes.
Do you think that it solves the static functions issues, replace a bigger problem with a smaller problem, or is it the exact same thing?

And also how to deal with classes that are not defined by us?

mauricioguaruja
Автор

I think the name of the library is a good hint about what to expect. Since it’s FastJson and not SlowJson one can deduct that speed is the primary goal here and static methods are indeed fast compared to a lot of small objects to instantiate. He probably made a conscious choice but who knows…

jonathansaindon
Автор

I’m calling this style of programming BOOP, Bugayenko Object Oriented Programming

ChrisAthanas
Автор

Егор, я узнал о вас только недавно, поэтому сам ответа на этот вопрос не знаю. Вопрос таков - считаете ли вы, что объектно-ориентированный (в вашем понимании) способ программирования должен применяться во всех сферах, или в каких-то специфических, например web dev. Лично я не могу представить большую, даже не AAA игру, написанную таким способом. Впринципе, скорее всего таким образом игру написать можно, но как её оптимизировать? Game dev такая сфера, где программисты по-настоящему ценят оптимизацию и рады когда язык это упрощает (Например SOA в Odin и Jai). Я слышал (От 3-о лица), что в одной из лекций (Кажется на JPoint) вы сказали про то, что в плане оптимизации нужно профайлить критические классы и там где нужно, идти на компромисс и делать статические методы. Это ладно, но как делать более сложные оптимизации, которых без нарушения большего количества принципов Elegant Objects, да и даже принципов "классического" ООП сделать фактически невозможно? Сразу оговорюсь - я не читал ни одну из ваших книг, так что если ответ лежит в одной из них, то прошу прощения

herrmitbusen
Автор

what about static constructor or static factory method(use to replace constructor)

trongphan
Автор

Егор, день добрый. Прошу прощение за вопрос не по теме, но ждать ли черно-белое айти?
Много месяцев простоя, а тем накопилось хот отбавляй. Хотелось бы услышать здравую позицию)

JohnSmith-sgov
Автор

Yegor, I really like your vision, thank you for the effort.
Could you just use "surface" in lieu of "square" 😅

yojokingly
Автор

The arguments for not using static/global functions are pretty flawed. I think it comes from an incomplete understanding of the encapsulation principle. What is (approximately) the measure of encapsulation? It is the amount of methods that can see and modify the internal state of an object. So the less methods an object has to realize its abstraction, the better it is encapsulated. Global functions provide an invariance to the object's behavior, since they compose public behaviors to achieve a higher level goal based on the input object/s. So if you put those global functions inside the objects, you are violating the encapsulation principle by breaking this invariance guarantee, making the objects more vulnerable to accidental side effects as the internals are open to be modified by more methods than necessary.

Let's see by an example what that all implies:

For example, let's consider the idea of a geometry object, like the circle. You might make an abstraction for the circle, and the purpose of the abstraction might be (for now) just the matehematical properties of this geometric object (like circumference and area). So you encapsulate the radius, and only expose the public behaviors like Circumference() and Area(). But later, you find out that you need functionality to compute the intersection of the circle with other geometric shapes. That's a whole new world of functions. And then, you might need even more functionality centered around the cirlce. So there are 3 things we can do here:

1. Just put the new functionality inside the Circle class (-> less encapsulation because more methods, leads to god objects)

2. Just make 1. first, but then start to encapsulate the related functions dealing with intersection etc. into new helper objects (like "CircleIntersectionComputer") living inside the circle. (-> becomes evident that the circle is not a single abstraction, but multiple independend abstractions mixed within the circle)

3. Make (or derive) a new Circle class for dealing with intersections (-> class explosion, as the granularity of behavior is a class rather than single functions that can be composed in any permutation -> unnecessary detours and amount of classes to solve problems that can already be solved directly by separation of concerns )

A little bit of elaboration on point 2., should be an eye opener :
If we don't want to violate encapsulation principle, the CircleIntersectionComputer should have no access to Circle's internals, but just receive a copy of its respective properties in order to compute the intersection with some other shape. So the next logical step is to put CircleIntersectionComputer completely out of the Circle because CircleIntersectionComputer is a clear barrier between the Circle's encapsulation. CircleIntersectionComputer is not a part of the circles internal state. In fact, the CircleIntersectionComputer might just be a set of functions, because it (potentially) doesn't have any internal state. So what you actually get are global functions that can flexibly match the particular problem you are trying to solve wit a circle, by simply exposing the necessary set of circle-functions required to solve the problem. Note how we automatically arrived at this solution (that you tried to avoid in the first place) just by following the encapsulation principle. We now have global functions or other systems dealing with the Circle as a consequence of the encapsulation principle.

As a rule of thumb, a good abstraction of a Circle (and any object) is only the behavior that is necessary for its core purpose, not the behavior that can be based on top of the already provided behavior. For a simple object like a Circle it happens to be just its representation, nothing more. So a circle doesn't have any behavior other than the data abstraction/validation of its internal state (getters setters). If your aim is modular architecture, a Cicrle shouldn't have behavior because any Circle functionality is orthogonal to its representation. So better let it be the responsibilty of other systems or global functions.

I think it is important to realize that not every object has the same level of behavior. Some are complex, but on the other end they can be very simple. It's a feature of the problem space, and if you don't model the problem space, you are not solving the problem. It's as simple as that, regardless what paradigm you are using, and actually a strong reason why "this use of oop" is bashed on so much. And in order to adapt to the problem it is necessary to keep the architecture flexible and open to extension.

Regarding your 3 particular arguments against global functions:

1. "They are unbreakable dependencies" All in all, this is a net-zero at worst here because the focus shifts from testing the circle to testing the circle-functions.

2. "They are eager, not lazy" And that is precisely what we want here. Simply put the function where it is needed (after the condition check), and the procedure will only do the stuff that is needed.

3. "They are not cohesive" That's correct, and that is precisely why they shouldn't be inside the object since we don't want to break the encapsulation. For instance, we don't have to test for an invalid state of the Circle (means negative radius, for example), as global functions cannot break the internal state of an encapsulated object. But if you put them inside the Circle, the internal state is not protected anymore. Even better, global functions that get a const Circle will never (accidently) modify the state of the Circle at all. Notice just how much vulnerablity space is gone by simply decoupling the representation from the functionality of the Circle.

SnakeEngine
Автор

1:35, wait what, piss on their code? 😂

TrayHardPlay
Автор

At least a static method is namespaced... A truly global function wouldn't be.

veganaiZe
Автор

Egor, why you're talking about this kind of things? Just curious

ilyamishchiy
welcome to shbcf.ru