Skip to content

Instantly share code, notes, and snippets.

@zolotyh
Last active February 17, 2025 16:50
Show Gist options
  • Save zolotyh/45196606fdd31db619de6ccfda5f7d61 to your computer and use it in GitHub Desktop.
Save zolotyh/45196606fdd31db619de6ccfda5f7d61 to your computer and use it in GitHub Desktop.

Пример 1: Простая диспетчеризация в React

Ситуация: У вас есть компонент, который должен отображать разные элементы в зависимости от типа данных (например, строка, число, массив).

Плохой код (без @arrows/multimethod):

function DataRenderer({ data }) {
  if (typeof data === 'string') {
    return <p>{data}</p>;
  } else if (typeof data === 'number') {
    return <span>{data}</span>;
  } else if (Array.isArray(data)) {
    return <ul>{data.map((item, index) => <li key={index}>{item}</li>)}</ul>;
  }
  return null;
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const renderData = multi(
  method('string', (data) => <p>{data}</p>),
  method('number', (data) => <span>{data}</span>),
  method(Array.isArray, (data) => <ul>{data.map((item, index) => <li key={index}>{item}</li>)}</ul>)
);

function DataRenderer({ data }) {
  return renderData(data);
}

Объяснение: Вместо множества if-else мы используем multimethod, чтобы динамически выбирать нужный метод рендеринга в зависимости от типа данных.


Пример 2: Диспетчеризация по нескольким аргументам в Angular

Ситуация: В Angular сервисе нужно обрабатывать разные типы запросов в зависимости от метода HTTP (GET, POST) и типа данных.

Плохой код (без @arrows/multimethod):

@Injectable({ providedIn: 'root' })
export class ApiService {
  handleRequest(method: string, data: any) {
    if (method === 'GET' && typeof data === 'string') {
      return this.handleGetRequest(data);
    } else if (method === 'POST' && Array.isArray(data)) {
      return this.handlePostRequest(data);
    }
    throw new Error('Unsupported request type');
  }

  private handleGetRequest(data: string) {
    // Логика для GET-запроса
  }

  private handlePostRequest(data: any[]) {
    // Логика для POST-запроса
  }
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const handleRequest = multi(
  method(['GET', 'string'], (method, data) => handleGetRequest(data)),
  method(['POST', Array.isArray], (method, data) => handlePostRequest(data))
);

@Injectable({ providedIn: 'root' })
export class ApiService {
  handleRequest(method: string, data: any) {
    return handleRequest(method, data);
  }

  private handleGetRequest(data: string) {
    // Логика для GET-запроса
  }

  private handlePostRequest(data: any[]) {
    // Логика для POST-запроса
  }
}

Объяснение: Мы используем multimethod для диспетчеризации по двум аргументам: методу HTTP и типу данных. Это делает код более читаемым и расширяемым.


Пример 3: Диспетчеризация в Vue

Ситуация: В Vue компоненте нужно обрабатывать разные события в зависимости от типа события и данных.

Плохой код (без @arrows/multimethod):

export default {
  methods: {
    handleEvent(event, data) {
      if (event === 'click' && typeof data === 'string') {
        this.handleClick(data);
      } else if (event === 'input' && typeof data === 'number') {
        this.handleInput(data);
      }
    },
    handleClick(data) {
      // Логика для клика
    },
    handleInput(data) {
      // Логика для ввода
    }
  }
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const handleEvent = multi(
  method(['click', 'string'], (event, data) => handleClick(data)),
  method(['input', 'number'], (event, data) => handleInput(data))
);

export default {
  methods: {
    handleEvent(event, data) {
      return handleEvent(event, data);
    },
    handleClick(data) {
      // Логика для клика
    },
    handleInput(data) {
      // Логика для ввода
    }
  }
}

Объяснение: Мы используем multimethod для обработки событий в зависимости от их типа и данных. Это упрощает добавление новых типов событий.


Пример 4: Диспетчеризация в RxJS

Ситуация: В RxJS потоке нужно обрабатывать разные типы данных (например, числа, строки, объекты) по-разному.

Плохой код (без @arrows/multimethod):

import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const source$ = of(42, 'hello', { key: 'value' });

source$.pipe(
  map(data => {
    if (typeof data === 'number') {
      return data * 2;
    } else if (typeof data === 'string') {
      return data.toUpperCase();
    } else if (typeof data === 'object') {
      return { ...data, processed: true };
    }
  })
).subscribe(console.log);

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const processData = multi(
  method('number', (data) => data * 2),
  method('string', (data) => data.toUpperCase()),
  method('object', (data) => ({ ...data, processed: true }))
);

const source$ = of(42, 'hello', { key: 'value' });

source$.pipe(
  map(data => processData(data))
).subscribe(console.log);

Объяснение: Мы используем multimethod для обработки разных типов данных в потоке RxJS. Это делает код более декларативным и легко расширяемым.


Пример 5: Диспетчеризация по нескольким аргументам в React

Ситуация: В React компоненте нужно выбирать стиль в зависимости от типа элемента и его состояния (активный/неактивный).

Плохой код (без @arrows/multimethod):

function getStyle(type, isActive) {
  if (type === 'button' && isActive) {
    return { backgroundColor: 'blue', color: 'white' };
  } else if (type === 'button' && !isActive) {
    return { backgroundColor: 'gray', color: 'black' };
  } else if (type === 'link' && isActive) {
    return { color: 'green' };
  } else if (type === 'link' && !isActive) {
    return { color: 'red' };
  }
  return {};
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const getStyle = multi(
  method(['button', true], () => ({ backgroundColor: 'blue', color: 'white' })),
  method(['button', false], () => ({ backgroundColor: 'gray', color: 'black' })),
  method(['link', true], () => ({ color: 'green' })),
  method(['link', false], () => ({ color: 'red' }))
);

function MyComponent({ type, isActive }) {
  const style = getStyle(type, isActive);
  return <div style={style}>Content</div>;
}

Объяснение: Мы используем multimethod для выбора стиля в зависимости от типа элемента и его состояния. Это делает код более читаемым и легко расширяемым.


Пример 6: Диспетчеризация в Angular с использованием нескольких аргументов

Ситуация: В Angular компоненте нужно выбирать шаблон в зависимости от типа данных и их состояния (например, загружены или нет).

Плохой код (без @arrows/multimethod):

@Component({
  selector: 'app-data-view',
  template: `
    <div *ngIf="isLoading">Loading...</div>
    <div *ngIf="!isLoading && typeof data === 'string'">{{ data }}</div>
    <div *ngIf="!isLoading && Array.isArray(data)">
      <ul>
        <li *ngFor="let item of data">{{ item }}</li>
      </ul>
    </div>
  `
})
export class DataViewComponent {
  @Input() data: any;
  @Input() isLoading: boolean;
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const getTemplate = multi(
  method([true, 'any'], () => `<div>Loading...</div>`),
  method([false, 'string'], (data) => `<div>${data}</div>`),
  method([false, Array.isArray], (data) => `
    <ul>
      ${data.map(item => `<li>${item}</li>`).join('')}
    </ul>
  `)
);

@Component({
  selector: 'app-data-view',
  template: `
    <div [innerHTML]="template"></div>
  `
})
export class DataViewComponent {
  @Input() data: any;
  @Input() isLoading: boolean;

  get template() {
    return getTemplate(this.isLoading, this.data);
  }
}

Объяснение: Мы используем multimethod для выбора шаблона в зависимости от состояния загрузки и типа данных. Это делает код более декларативным и легко расширяемым.


Пример 7: Диспетчеризация в Vue с использованием нескольких аргументов

Ситуация: В Vue компоненте нужно выбирать метод обработки данных в зависимости от типа события и состояния компонента.

Плохой код (без @arrows/multimethod):

export default {
  data() {
    return {
      isActive: false
    };
  },
  methods: {
    handleEvent(event, data) {
      if (event === 'click' && this.isActive) {
        this.handleActiveClick(data);
      } else if (event === 'click' && !this.isActive) {
        this.handleInactiveClick(data);
      } else if (event === 'hover' && this.isActive) {
        this.handleActiveHover(data);
      }
    },
    handleActiveClick(data) {
      // Логика для активного клика
    },
    handleInactiveClick(data) {
      // Логика для неактивного клика
    },
    handleActiveHover(data) {
      // Логика для активного ховера
    }
  }
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const handleEvent = multi(
  method(['click', true], (event, data, vm) => vm.handleActiveClick(data)),
  method(['click', false], (event, data, vm) => vm.handleInactiveClick(data)),
  method(['hover', true], (event, data, vm) => vm.handleActiveHover(data))
);

export default {
  data() {
    return {
      isActive: false
    };
  },
  methods: {
    handleEvent(event, data) {
      return handleEvent(event, data, this);
    },
    handleActiveClick(data) {
      // Логика для активного клика
    },
    handleInactiveClick(data) {
      // Логика для неактивного клика
    },
    handleActiveHover(data) {
      // Логика для активного ховера
    }
  }
}

Объяснение: Мы используем multimethod для обработки событий в зависимости от их типа и состояния компонента. Это делает код более читаемым и легко расширяемым.


Пример 8: Диспетчеризация в RxJS с использованием нескольких аргументов

Ситуация: В RxJS потоке нужно обрабатывать данные в зависимости от их типа и состояния (например, успешно или с ошибкой).

Плохой код (без @arrows/multimethod):

import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const source$ = of({ type: 'success', data: 42 }, { type: 'error', data: 'Oops!' });

source$.pipe(
  map(response => {
    if (response.type === 'success' && typeof response.data === 'number') {
      return response.data * 2;
    } else if (response.type === 'error' && typeof response.data === 'string') {
      return `Error: ${response.data}`;
    }
  })
).subscribe(console.log);

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const processResponse = multi(
  method(['success', 'number'], (type, data) => data * 2),
  method(['error', 'string'], (type, data) => `Error: ${data}`)
);

const source$ = of({ type: 'success', data: 42 }, { type: 'error', data: 'Oops!' });

source$.pipe(
  map(response => processResponse(response.type, response.data))
).subscribe(console.log);

Объяснение: Мы используем multimethod для обработки данных в зависимости от их типа и состояния. Это делает код более декларативным и легко расширяемым.


Пример 9: Диспетчеризация в React с использованием пользовательских предикатов

Ситуация: В React компоненте нужно выбирать метод рендеринга в зависимости от сложных условий (например, данных и их длины).

Плохой код (без @arrows/multimethod):

function renderContent(data) {
  if (Array.isArray(data) && data.length > 5) {
    return <ul>{data.map((item, index) => <li key={index}>{item}</li>)}</ul>;
  } else if (Array.isArray(data) && data.length <= 5) {
    return <p>{data.join(', ')}</p>;
  } else if (typeof data === 'string') {
    return <h1>{data}</h1>;
  }
  return null;
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const renderContent = multi(
  method(
    (data) => Array.isArray(data) && data.length > 5,
    (data) => <ul>{data.map((item, index) => <li key={index}>{item}</li>)}</ul>
  ),
  method(
    (data) => Array.isArray(data) && data.length <= 5,
    (data) => <p>{data.join(', ')}</p>
  ),
  method('string', (data) => <h1>{data}</h1>)
);

function MyComponent({ data }) {
  return renderContent(data);
}

Объяснение: Мы используем multimethod с пользовательскими предикатами для выбора метода рендеринга в зависимости от сложных условий. Это делает код более гибким и читаемым.


Пример 10: Диспетчеризация в Angular с использованием пользовательских предикатов

Ситуация: В Angular сервисе нужно выбирать метод обработки данных в зависимости от сложных условий (например, данных и их структуры).

Плохой код (без @arrows/multimethod):

@Injectable({ providedIn: 'root' })
export class DataService {
  processData(data: any) {
    if (Array.isArray(data) && data.every(item => typeof item === 'number')) {
      return this.processNumbers(data);
    } else if (typeof data === 'object' && data.hasOwnProperty('key')) {
      return this.processObject(data);
    }
    throw new Error('Unsupported data type');
  }

  private processNumbers(data: number[]) {
    // Логика для обработки чисел
  }

  private processObject(data: { key: string }) {
    // Логика для обработки объекта
  }
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const processData = multi(
  method(
    (data) => Array.isArray(data) && data.every(item => typeof item === 'number'),
    (data) => processNumbers(data)
  ),
  method(
    (data) => typeof data === 'object' && data.hasOwnProperty('key'),
    (data) => processObject(data)
  )
);

@Injectable({ providedIn: 'root' })
export class DataService {
  processData(data: any) {
    return processData(data);
  }

  private processNumbers(data: number[]) {
    // Логика для обработки чисел
  }

  private processObject(data: { key: string }) {
    // Логика для обработки объекта
  }
}

Объяснение: Мы используем multimethod с пользовательскими предикатами для выбора метода обработки данных в зависимости от сложных условий. Это делает код более гибким и читаемым.


Пример 11: Диспетчеризация в Vue с использованием пользовательских предикатов

Ситуация: В Vue компоненте нужно выбирать метод обработки данных в зависимости от сложных условий (например, данных и их структуры).

Плохой код (без @arrows/multimethod):

export default {
  methods: {
    processData(data) {
      if (Array.isArray(data) && data.every(item => typeof item === 'string')) {
        return this.processStrings(data);
      } else if (typeof data === 'object' && data.hasOwnProperty('id')) {
        return this.processObject(data);
      }
      throw new Error('Unsupported data type');
    },
    processStrings(data) {
      // Логика для обработки строк
    },
    processObject(data) {
      // Логика для обработки объекта
    }
  }
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const processData = multi(
  method(
    (data) => Array.isArray(data) && data.every(item => typeof item === 'string'),
    (data) => processStrings(data)
  ),
  method(
    (data) => typeof data === 'object' && data.hasOwnProperty('id'),
    (data) => processObject(data)
  )
);

export default {
  methods: {
    processData(data) {
      return processData(data);
    },
    processStrings(data) {
      // Логика для обработки строк
    },
    processObject(data) {
      // Логика для обработки объекта
    }
  }
}

Объяснение: Мы используем multimethod с пользовательскими предикатами для выбора метода обработки данных в зависимости от сложных условий. Это делает код более гибким и читаемым.


Пример 12: Диспетчеризация в RxJS с использованием пользовательских предикатов

Ситуация: В RxJS потоке нужно обрабатывать данные в зависимости от сложных условий (например, данных и их структуры).

Плохой код (без @arrows/multimethod):

import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const source$ = of([1, 2, 3], { id: 1, name: 'John' }, 'hello');

source$.pipe(
  map(data => {
    if (Array.isArray(data) && data.every(item => typeof item === 'number')) {
      return data.map(item => item * 2);
    } else if (typeof data === 'object' && data.hasOwnProperty('id')) {
      return { ...data, processed: true };
    } else if (typeof data === 'string') {
      return data.toUpperCase();
    }
  })
).subscribe(console.log);

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const processData = multi(
  method(
    (data) => Array.isArray(data) && data.every(item => typeof item === 'number'),
    (data) => data.map(item => item * 2)
  ),
  method(
    (data) => typeof data === 'object' && data.hasOwnProperty('id'),
    (data) => ({ ...data, processed: true })
  ),
  method('string', (data) => data.toUpperCase())
);

const source$ = of([1, 2, 3], { id: 1, name: 'John' }, 'hello');

source$.pipe(
  map(data => processData(data))
).subscribe(console.log);

Объяснение: Мы используем multimethod с пользовательскими предикатами для обработки данных в зависимости от сложных условий. Это делает код более декларативным и легко расширяемым.


Пример 13: Диспетчеризация в React с использованием нескольких аргументов и пользовательских предикатов

Ситуация: В React компоненте нужно выбирать метод рендеринга в зависимости от нескольких аргументов и сложных условий.

Плохой код (без @arrows/multimethod):

function renderContent(type, data) {
  if (type === 'list' && Array.isArray(data) && data.length > 5) {
    return <ul>{data.map((item, index) => <li key={index}>{item}</li>)}</ul>;
  } else if (type === 'list' && Array.isArray(data) && data.length <= 5) {
    return <p>{data.join(', ')}</p>;
  } else if (type === 'text' && typeof data === 'string') {
    return <h1>{data}</h1>;
  }
  return null;
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const renderContent = multi(
  method(
    ['list', (data) => Array.isArray(data) && data.length > 5],
    (type, data) => <ul>{data.map((item, index) => <li key={index}>{item}</li>)}</ul>
  ),
  method(
    ['list', (data) => Array.isArray(data) && data.length <= 5],
    (type, data) => <p>{data.join(', ')}</p>
  ),
  method(['text', 'string'], (type, data) => <h1>{data}</h1>)
);

function MyComponent({ type, data }) {
  return renderContent(type, data);
}

Объяснение: Мы используем multimethod для выбора метода рендеринга в зависимости от нескольких аргументов и сложных условий. Это делает код более гибким и читаемым.


Пример 14: Диспетчеризация в Angular с использованием нескольких аргументов и пользовательских предикатов

Ситуация: В Angular сервисе нужно выбирать метод обработки данных в зависимости от нескольких аргументов и сложных условий.

Плохой код (без @arrows/multimethod):

@Injectable({ providedIn: 'root' })
export class DataService {
  processData(type: string, data: any) {
    if (type === 'numbers' && Array.isArray(data) && data.every(item => typeof item === 'number')) {
      return this.processNumbers(data);
    } else if (type === 'object' && typeof data === 'object' && data.hasOwnProperty('key')) {
      return this.processObject(data);
    }
    throw new Error('Unsupported data type');
  }

  private processNumbers(data: number[]) {
    // Логика для обработки чисел
  }

  private processObject(data: { key: string }) {
    // Логика для обработки объекта
  }
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const processData = multi(
  method(
    ['numbers', (data) => Array.isArray(data) && data.every(item => typeof item === 'number')],
    (type, data) => processNumbers(data)
  ),
  method(
    ['object', (data) => typeof data === 'object' && data.hasOwnProperty('key')],
    (type, data) => processObject(data)
  )
);

@Injectable({ providedIn: 'root' })
export class DataService {
  processData(type: string, data: any) {
    return processData(type, data);
  }

  private processNumbers(data: number[]) {
    // Логика для обработки чисел
  }

  private processObject(data: { key: string }) {
    // Логика для обработки объекта
  }
}

Объяснение: Мы используем multimethod для выбора метода обработки данных в зависимости от нескольких аргументов и сложных условий. Это делает код более гибким и читаемым.


Пример 15: Диспетчеризация в Vue с использованием нескольких аргументов и пользовательских предикатов

Ситуация: В Vue компоненте нужно выбирать метод обработки данных в зависимости от нескольких аргументов и сложных условий.

Плохой код (без @arrows/multimethod):

export default {
  methods: {
    processData(type, data) {
      if (type === 'numbers' && Array.isArray(data) && data.every(item => typeof item === 'number')) {
        return this.processNumbers(data);
      } else if (type === 'object' && typeof data === 'object' && data.hasOwnProperty('id')) {
        return this.processObject(data);
      }
      throw new Error('Unsupported data type');
    },
    processNumbers(data) {
      // Логика для обработки чисел
    },
    processObject(data) {
      // Логика для обработки объекта
    }
  }
}

Хороший код (с @arrows/multimethod):

import { multi, method } from '@arrows/multimethod';

const processData = multi(
  method(
    ['numbers', (data) => Array.isArray(data) && data.every(item => typeof item === 'number')],
    (type, data) => processNumbers(data)
  ),
  method(
    ['object', (data) => typeof data === 'object' && data.hasOwnProperty('id')],
    (type, data) => processObject(data)
  )
);

export default {
  methods: {
    processData(type, data) {
      return processData(type, data);
    },
    processNumbers(data) {
      // Логика для обработки чисел
    },
    processObject(data) {
      // Логика для обработки объекта
    }
  }
}

Объяснение: Мы используем multimethod для выбора метода обработки данных в зависимости от нескольких аргументов и сложных условий. Это делает код более гибким и читаемым.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment