Теория 📔
July 30, 2024

Про "Функциональную зависть"

"Функциональная зависть" (Functionality Envy) - это термин из области объектно-ориентированного программирования, описывающий ситуацию, когда метод одного класса чрезмерно использует данные другого класса. Это говорит о том, что метод "завидует" другому классу, желая использовать его данные и функциональность, вместо того чтобы выполнять задачи, которые он должен выполнять внутри своего класса.

Давайте рассмотрим пример этой проблемы в контексте Angular и TypeScript.

Представим, что у нас есть два класса: UserService и UserComponent. UserService управляет данными пользователя, а UserComponent отвечает за отображение этих данных.

Пример кода с функциональной завистью:

// user.service.ts
export class UserService {
  private user = {
    id: 1,
    name: 'John Doe',
    email: 'john.doe@example.com'
  };

  getUser() {
    return this.user;
  }

  getUserName() {
    return this.user.name;
  }

  getUserEmail() {
    return this.user.email;
  }
}

// user.component.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user',
  template: `
    <div>
      <h1>{{ userName }}</h1>
      <p>{{ userEmail }}</p>
    </div>
  `
})
export class UserComponent implements OnInit {
  userName: string;
  userEmail: string;

  constructor(private userService: UserService) {}

  ngOnInit() {
    const user = this.userService.getUser();
    this.userName = user.name;
    this.userEmail = user.email;
  }
}

В этом примере UserComponent напрямую обращается к данным пользователя через метод getUser в UserService и использует их для своих нужд. Это типичный пример функциональной зависти, так как UserComponent чрезмерно зависит от структуры данных, предоставляемых UserService.

Как улучшить:

// user.service.ts
export class UserService {
  private user = {
    id: 1,
    name: 'John Doe',
    email: 'john.doe@example.com'
  };

  getUserName() {
    return this.user.name;
  }

  getUserEmail() {
    return this.user.email;
  }
}

// user.component.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user',
  template: `
    <div>
      <h1>{{ userName }}</h1>
      <p>{{ userEmail }}</p>
    </div>
  `
})
export class UserComponent implements OnInit {
  userName: string;
  userEmail: string;

  constructor(private userService: UserService) {}

  ngOnInit() {
    this.userName = this.userService.getUserName();
    this.userEmail = this.userService.getUserEmail();
  }
}

Теперь UserComponent больше не зависит от внутренней структуры данных пользователя. Вместо этого он использует методы getUserName и getUserEmail, предоставляемые UserService. Это улучшает инкапсуляцию и уменьшает зависимость между компонентами, решая проблему функциональной зависти.