Hello! At the moment I am studying OOP and I am confronted with a misunderstanding of the phrase “sending a message”.

Here is a very simplified presentation: Suppose we have two classes X and Y. In class X, there is a getData method that returns some data. In class Y, there is a handleData method that processes data and returns new ones. Here is the code:

class X { getData() { return 'some data'; } } class Y { handleData(data) { return data + 'some operation on data'; } } // создаём объекты const x = new X(); const y = new Y(); // вызываем методы let data = x.getData(); let handledData = y.handleData(data); 

And here's the actual question: Can we say from the code above that object y sends a message to object x ? does it use data from object x ?

Or I’m mistaken and the term “send a message” to OOP is if the object x were used inside the object y the implementation would be:

 class X { getData() { return 'some data'; } } class Y { constructor() { this._x = new X(); } handleData() { let data = this._x.getData(); return data + 'some operation on data'; } } // создаём объект const y = new Y(); // вызываем метод let handledData = y.handleData(); 

1 answer 1

In the first version, object х simply returns the data. It does not interact with the object у any way. He does not know anything about him at all; moreover, he interacts with him through the global variable data . y does y interact with х . it simply receives some data stored in the global variable data (it is not clear how the data got there) as input to its method. This method is bad because an intermediary is used to process information as a variable in the global scope.

In the second variant, you already have class objects interacting with each other, but what you wrote is called composition and this is not good, I would even say that this is bad and that is why. Imagine that at one point you decide to rewrite the class Y (even to rename it) all the classes that your Y used to explicitly have to rewrite. Whereas if you use aggregation (and if you dig deeper into the "dependency injection" pattern), then your second example can be rewritten as

 class X { getData() { return 'some data'; } } class Y { constructor(dataSource) { this._x = dataSource; } handleData() { let data = this._x.getData(); return data + 'some operation on data'; } } // создаём объект const y = new Y(new X); // вызываем метод let handledData = y.handleData(); 

As a result, you pass to your Y object which is supposed to have a getData method. Ie you can at any time on the stage

 const y = new Y(new X); 

replace X at least Z at least W if only there would be a getData method.

But let's imagine that we may not know in advance who will need data from the class X getData method ...

For a starter, just for your needs - объект y посылает сообщение объекту x look at the odserver pattern

 class X { constructor () { this.subscribers = [] } subscribe (subscriber) { this.subscribers.push(subscriber) } releaseData() { this.subscribers.forEach(subscriber => subscriber.handleData('some data')); } } class Y { handleData(data) { console.log(data + 'some operation on data in Y'); } } // создаём источника данных const x = new X(); // создаем подписчика const y = new Y(); // подписываемся на событие генерации данных x.subscribe(y); // инициируем отправку данных и получаем их в `y` x.releaseData()