データ指向プログラミングとは何か
データ指向プログラミング(DOP)を学びはじめた。
データ指向プログラミングの原則
- データとコード(ふるまい)を分離する
- データエンティティは汎用的なデータ構造にする
- コードモジュールはステートレスな関数にする
- データはイミュータブルにする
オブジェクト指向プログラミング(OOP)の場合
class Book {
id: string
title: string
}
class User {
id: string
name: string
}
class Author extends User {
equal(target: this) {
return this.id === target.id
}
}
class BookItem {
book: Book
authors: Author[]
}
class Catalog {
#bookItems: BookItem[] = []
addBookItem(bookItem: BookItem) {
this.#bookItems.push(bookItem)
}
findByAuthor(author: Author): Book[] {
return this.#bookItems.filter(item => item.authors.some(a => a.equal(author)))
}
}
const book = catalog.findByAuthor(author)
データ指向プログラミングの場合
書籍ではデータエンティティをデータクラス(ふるまいを持たないデータだけのクラス)で実装してたけど、それだとあまり旨味を感じられない気もする。
// データエンティティ(制約:汎用的なデータ構造)
type Book = { id: string, title: string }
type User = { id: string, name: string }
type Author = User & { ... }
type BookItem = { book: Book, authors: Author[] }
// コードモジュール(制約:ステートレス)
const Catalog = {
findByAuthor(bookItemData: BookItem[], author: Author) {
return bookItemData
.filter(book => book.authors
.some(a => a.id === author.id)
)
}
}
const book1: Book = { id: '1', title: 'one' }
const book2: Book = { id: '2', title: 'two' }
const author1: Author = { id: 'a01', name: 'aaa' }
const author2: Author = { id: 'b01', name: 'bbb' }
const bookItem1: BookItem = { book: book1, authors: [author1, author2]}
const bookItem2: BookItem = { book: book2, authors: [author2]}
const bookItemData: BookItem[] = [bookItem1, bookItem2]
const book = Catalog.findByAuthor(bookItemData, author1)
感想
JavaScriptでDOPをやるには、言語仕様で縛ることができないためlodashのようなコレクション操作ライブラリやImmutable.jsのようなオブジェクトの変更を禁止するライブラリがないとつらそう。なくてもできなくはないが、チーム開発における運用が大変になる。
データをClassではなくプレーンなオブジェクト(≒汎用的なデータ構造)として扱う部分においては、JavaScriptフレームワークと相性が良い。Classを使った場合、メンバ変数の更新に対してフレームワークが検知できないためリアクティブにならない。
DOPの原則は、昨今のソフトウェア設計におけるベストプラクティスと合致しているのでアリより。