Анатомия композаблов
DISCLAIMER: сравнение натянутое и заведомо раздутое, но в нем есть и зерно истины
возможно это прозвучит дико, но композаблы не шибко отличаются от обычного ООП, только описание у них императивное вместо декларативного. И многих это действительно удивляет. Так что я решил показать это более наглядно
function useA () { // имя класса
const b = ref() // поле класса
const c = ref() // поле класса 2
const sum = computed(() => b.value + c.value) // getter (и возможно setter)
function swap() {} // метод класса
// тут может быть ваша логика конструктора
// и даже деструктор доступен
onScopeDispose(() => { ... })
return {
b, // теперь b публичное поле класса (а вот С приватное)
sum // публичный метод
}
}
Вы можете возразить: а как же 3 столпа ООП наследование/инкапсуляция/полиморфизм.
С инкапсуляцией разобраться просто: композаблы и нужны, чтобы инкапсулировать логику в 1 месте (как сокрытие работает мы уже тоже рассмотрели)
Что насчет полиморфизма: с ним все замечательно, просто мы применяем его редко:
interface A {
(): { // описываем параметра конструктора
b: Ref
swap(): void // описали публичный интерфейс
}
}
const useA1: A = () => { ... }
const useA2: A = () => { ... }
A1 и A2 реализуют один интерфейс и мы можем подменять их в зависимости от ситуации, 90% нам это не понадобится, но если сильно хочется то возможно
А где наследование то? Ну с наследованием ситуация веселе. Сейчас такая тенденция, что наследования стараются избегать всячески предлагая вместо него использовать композицю, но многим лень, так как наследование написать на классах проще и удобнее чем композицю (особенно если хочется сохранить прежний интерфейс). С композаблами ровно обратная ситуация: мы легко можем использовать композицию, но наследование становится болезненным
(чему я очень рад!)function useA() {} // base
function useB() { // композиция ❤️
const a = useA() // изи
const { b, swap } = useA() // внедрение тоже легкое
...
}
const useB = ({...}: {...} & Parameters) => { // наследование 🙈
const a = useA() // взяли и
const c = ref()
return {...a, с} // вернули
...
}
Если кому интересно проверить теорию на прочность, то велком в комментарии. Но основная суть поста показать, что мы отчасти остались в тех же рамках только с переходом от декларативности к императивности, чтобы иметь большую гибкость в действиях