導入
オブジェクト指向設計は、ソフトウェア開発における重要なアプローチの一つであり、特に大規模なシステムにおいてその真価を発揮します。しかし、実際の開発現場では、オブジェクト指向の原則を誤解し、アンチパターンに陥ることが少なくありません。この記事では、TypeScriptを用いて、よく見られるアンチパターンとその改善策について具体的なシチュエーションを通じて解説します。
教科書レベルの解説(オブジェクト指向設計)
重要な概念の整理
オブジェクト指向設計は、カプセル化、継承、ポリモーフィズムといった基本的な概念から成り立っています。これらの原則を適切に利用することで、コードの再利用性や保守性が向上します。しかし、これらの概念を誤って適用すると、逆に複雑さを増し、コードの可読性を低下させることがあります。
コード例(TypeScript)
class User {
constructor(public name: string, public age: number) {}
}
class Admin extends User {
constructor(name: string, age: number, public permissions: string[]) {
super(name, age);
}
addPermission(permission: string) {
this.permissions.push(permission);
}
}
const admin = new Admin("Alice", 30, ["read", "write"]);
admin.addPermission("delete");
コードの行ごとの解説
class User– ユーザーを表現する基本クラスを定義。constructor(public name: string, public age: number)– ユーザーの名前と年齢を初期化。class Admin extends User– ユーザーを拡張した管理者クラスを定義。constructor(name: string, age: number, public permissions: string[])– 管理者の特権を初期化。addPermission(permission: string)– 新しい権限を追加するメソッド。const admin = new Admin("Alice", 30, ["read", "write"])– 管理者インスタンスを作成。admin.addPermission("delete")– 権限を追加。
アンチパターン編
上記のコードは一見すると正しく見えますが、実際にはいくつかの問題を抱えています。特に、継承の過剰使用が挙げられます。AdminクラスはUserクラスから継承していますが、AdminがUserのすべての特性を持つ必要があるかは疑問です。このように、クラス間の関係が不明確になると、コードのメンテナンスが難しくなります。
改善策として、コンポジションを考慮することが有効です。AdminクラスがUserクラスを持つ形に変更することで、より柔軟な設計が可能になります。以下はその改善例です。
class User {
constructor(public name: string, public age: number) {}
}
class Admin {
private user: User;
public permissions: string[];
constructor(name: string, age: number, permissions: string[]) {
this.user = new User(name, age);
this.permissions = permissions;
}
addPermission(permission: string) {
this.permissions.push(permission);
}
}
const admin = new Admin("Alice", 30, ["read", "write"]);
admin.addPermission("delete");
まとめ
- オブジェクト指向設計では、継承の使用を慎重に行うことが求められます。
- コンポジションを利用することで、より柔軟でメンテナンスしやすいコードを実現できます。
- 実際の業務では、アンチパターンを意識し、適切な設計を心がけることが重要です。