Ситуация: У вас есть компонент, который должен отображать разные элементы в зависимости от типа данных (например, строка, число, массив).
Плохой код (без @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
, чтобы динамически выбирать нужный метод рендеринга в зависимости от типа данных.
Ситуация: В 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 и типу данных. Это делает код более читаемым и расширяемым.
Ситуация: В 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
для обработки событий в зависимости от их типа и данных. Это упрощает добавление новых типов событий.
Ситуация: В 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. Это делает код более декларативным и легко расширяемым.
Ситуация: В 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
для выбора стиля в зависимости от типа элемента и его состояния. Это делает код более читаемым и легко расширяемым.
Ситуация: В 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
для выбора шаблона в зависимости от состояния загрузки и типа данных. Это делает код более декларативным и легко расширяемым.
Ситуация: В 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
для обработки событий в зависимости от их типа и состояния компонента. Это делает код более читаемым и легко расширяемым.
Ситуация: В 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
для обработки данных в зависимости от их типа и состояния. Это делает код более декларативным и легко расширяемым.
Ситуация: В 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
с пользовательскими предикатами для выбора метода рендеринга в зависимости от сложных условий. Это делает код более гибким и читаемым.
Ситуация: В 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
с пользовательскими предикатами для выбора метода обработки данных в зависимости от сложных условий. Это делает код более гибким и читаемым.
Ситуация: В 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
с пользовательскими предикатами для выбора метода обработки данных в зависимости от сложных условий. Это делает код более гибким и читаемым.
Ситуация: В 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
для выбора метода обработки данных в зависимости от нескольких аргументов и сложных условий. Это делает код более гибким и читаемым.