概要
単一責任の原則(SRP)は、**「クラスは変更する理由を1つだけ持つべき」**というSOLID原則の1つである。「責任」とは変更の軸を意味し、変更の影響範囲を限定することで保守性・テスト容易性・再利用性が向上する。
単一責任の原則(SRP)は、**「クラスは変更する理由を1つだけ持つべき」**というSOLID原則の1つである。「責任」とは変更の軸を意味し、変更の影響範囲を限定することで保守性・テスト容易性・再利用性が向上する。
SRPの核心は「変更管理」である。「責任」とは変更の軸を意味する。あるクラスを変更する理由が複数ある場合、そのクラスは複数の責任を持つ。
// ❌ SRP違反:データ取得、バリデーション、UI表示を1つに集約
function UserProfile() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(false);
// データ取得責任
useEffect(() => {
fetch('/api/user/123')
.then(res => res.json())
.then(setUser);
}, []);
// バリデーション責任
const validateEmail = (email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
// フォーム送信責任
const handleSubmit = async (data: User) => {
if (!validateEmail(data.email)) return;
await fetch('/api/user/123', {
method: 'PUT',
body: JSON.stringify(data),
});
};
// UI表示責任
if (loading) return <div>Loading...</div>;
return <form onSubmit={...}>{/* フォームUI */}</form>;
}
データ取得、バリデーション、API呼び出し、UI表示の4つの責任を持つため、異なる理由で変更が発生する。
// ✅ SRP準拠:責任ごとに分離
// hooks/useUser.ts - データ取得と状態管理のみ
function useUser(userId: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
fetch(`/api/user/${userId}`)
.then((res) => res.json())
.then(setUser);
}, [userId]);
const updateUser = async (data: User) => {
const res = await fetch(`/api/user/${userId}`, {
method: 'PUT',
body: JSON.stringify(data),
});
setUser(await res.json());
};
return { user, loading, updateUser };
}
// utils/validators.ts - バリデーションのみ
export const validateEmail = (email: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
// components/UserForm.tsx - UI表示のみ
function UserForm({ user, onSubmit }: UserFormProps) {
return (
<form onSubmit={onSubmit}>
<input name="name" defaultValue={user.name} />
<input name="email" defaultValue={user.email} />
<button>Save</button>
</form>
);
}
// 使用例
function UserProfile() {
const { user, loading, updateUser } = useUser('123');
if (loading) return <div>Loading...</div>;
return <UserForm user={user} onSubmit={updateUser} />;
}
各モジュールが単一責任を持ち、変更の影響が局所化される。useUser
はデータ管理、validators
はバリデーション、UserForm
はUI表示のみを担当する。
React.memo
で最適化しやすいSRPは「クラスは変更する理由を1つだけ持つべき」という原則である。フロントエンド開発では、コンポーネント・フック・ユーティリティの責任を分離することで、以下が実現される。