介绍
SOLID 原则是面向对象设计的五个基本原则,旨在帮助开发者创建可维护、可扩展和可重用的代码。虽然这些原则起源于面向对象编程,但它们可以有效地应用于 JavaScript
。本文通过JS
中的真实示例解释了每个原则。
1.单一职责原则 (Single Responsibility Principle, SRP)
原则: 每个类或模块应该只有一个单一的职责,即只负责一项功能。这样可以降低类之间的耦合度,提高代码的可维护性。
例如下面的 react
代码,我们经常看到组件负责太多事情——例如管理UI
和业务逻辑。
function UserProfile({ userId }) { const [user, setUser] = useState(null); useEffect(() => { fetchUserData(); }, [userId]); async function fetchUserData() { const response = await fetch(`/api/users/${userId}`); const data = await response.json(); setUser(data); } return <div>{user?.name}</div>; }
UserProfile
组件违反了SRP
,因为它同时处理UI
渲染和数据提取。重构之后
// Custom hook for fetching user data function useUserData(userId) { const [user, setUser] = useState(null); useEffect(() => { async function fetchUserData() { const response = await fetch(`/api/users/${userId}`); const data = await response.json(); setUser(data); } fetchUserData(); }, [userId]); return user; } // UI Component function UserProfile({ userId }) { const user = useUserData(userId); // Moved data fetching logic to a hook return <div>{user?.name}</div>; }
我们将数据获取逻辑与 UI
分离,让每个部分负责单个任务。
2.开放/封闭原则(OCP)
原则: 软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。这意味着你应该能够通过扩展现有代码来添加新功能,而不需要修改已有的代码。
例如下面的 JavaScript
代码,有一个运行良好的表单验证功能,但将来可能需要额外的验证逻辑。每当您需要新的验证规则时,您就必须修改此功能,从而违反 OCP
function validate(input) { if (input.length < 5) { return 'Input is too short'; } if (!input.includes('@')) { return 'Invalid email'; } return 'Valid input'; }
重构之后,我们可以扩展验证规则,而不需要修改原有的验证函数,遵循OCP
function validate(input, rules) { return rules.map(rule => rule(input)).find(result => result !== 'Valid') || 'Valid input'; } const lengthRule = input => input.length >= 5 ? 'Valid' : 'Input is too short'; const emailRule = input => input.includes('@') ? 'Valid' : 'Invalid email'; validate('test@domain.com', [lengthRule, emailRule]);
3.里氏替换原则(LSP)
原则: 子类应该能够替代其父类,并且在程序中可以无缝使用。换句话说,使用子类的对象时,程序的正确性不应受到影响。
例如react
中,当使用高阶组件(HOC
)或有条件地渲染不同组件时,LSP
有助于确保所有组件的行为都可预测
但是下面的代码中,组件不能互换,因为它们使用不同的 props
(onClick
与 href
)。
function Button({ onClick }) { return <button onClick={onClick}>Click me</button>; } function LinkButton({ href }) { return <a href={href}>Click me</a>; } // Inconsistent use of onClick and href makes substitution difficult <Button onClick={() => {}} />; <LinkButton href="/home" />;
重构之后,两个组件(Button
和 LinkButton
)在语义上都是正确的,遵守 HTML 可访问性标准,并且在遵循 LSP 时行为一致
function Actionable({ onClick, href, children }) { if (href) { return <a href={href}>{children}</a>; } else { return <button onClick={onClick}>{children}</button>; } } function Button({ onClick }) { return <Actionable onClick={onClick}>Click me</Actionable>; } function LinkButton({ href }) { return <Actionable href={href}>Go Home</Actionable>; }
4.接口隔离原则(ISP)
原则: 不应该强迫一个类依赖于它不使用的方法。应该将大接口分解成小接口,以便实现更精确的依赖关系,降低类之间的耦合度。
例如下面的 React
组件有时会收到不必要的 props
,导致代码紧密耦合且臃肿,
function MultiPurposeComponent({ user, posts, comments }) { return ( <div> <UserProfile user={user} /> <UserPosts posts={posts} /> <UserComments comments={comments} /> </div> ); }
重构之后,通过将组件拆分为更小的组件,每个组件仅依赖于它实际使用的数据。
function UserProfileComponent({ user }) { return <UserProfile user={user} />; } function UserPostsComponent({ posts }) { return <UserPosts posts={posts} />; } function UserCommentsComponent({ comments }) { return <UserComments comments={comments} />; }
5.依赖倒置原则(DIP)
原则: 高级模块不应该依赖于低级模块。两者都应该依赖于抽象(例如接口)
下面的代码中,UserComponent
与 fetchUser
函数紧密耦合。
function fetchUser(userId) { return fetch(`/api/users/${userId}`).then(res => res.json()); } function UserComponent({ userId }) { const [user, setUser] = useState(null); useEffect(() => { fetchUser(userId).then(setUser); }, [userId]); return <div>{user?.name}</div>; }
重构之后,通过将 fetchUserData
注入组件,我们可以轻松地交换实现以进行测试或用于不同的用例。
function UserComponent({ userId, fetchUserData }) { const [user, setUser] = useState(null); useEffect(() => { fetchUserData(userId).then(setUser); }, [userId, fetchUserData]); return <div>{user?.name}</div>; } // Usage <UserComponent userId={1} fetchUserData={fetchUser} />;
结论
SOLID
原则对于确保您的代码干净、可维护且可扩展非常有效,即使在 JavaScript
和 TypeScript
框架中也是如此。应用这些原则使开发人员能够编写灵活且可重复使用的代码,这些代码易于随着需求的发展而扩展和重构。通过遵循 SOLID
,您可以使您的代码库变得强大并为未来的增长做好准备
本文翻译的原文地址:Applying SOLID Principles in JavaScript and TypeScript Framework
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/qdvuejs/1278.html