写程序的时候,经常要决定怎么组织代码结构。比如做用户登录功能,有人喜欢用类继承,有人偏爱依赖注入。这两种方式都能实现功能,但背后的设计思路差别不小。
类继承:父子关系的代码复用
类继承就像家庭里的父子传承。父亲会的技能,儿子不用再学就能用。在代码里,子类可以继承父类的方法和属性。
比如有个基础的用户类:
class BaseUser {
public function login() {
echo "用户登录中...";
}
}
普通用户和管理员都用这个基础功能,就可以通过继承扩展:
class AdminUser extends BaseUser {
public function deletePost() {
echo "删除文章";
}
}
这样写起来简单直观,但问题也明显。一旦父类改了,所有子类都可能受影响。就像家里父亲改了家规,全家都得跟着变。
依赖注入:灵活搭配的组合方式
依赖注入更像是拼乐高。每个模块独立做好,然后按需组装。比如登录功能不再写死在用户类里,而是作为一个服务单独存在。
class LoginService {
public function performLogin() {
echo "执行登录逻辑";
}
}
用户类通过构造函数接收这个服务:
class User {
private $loginService;
public function __construct(LoginService $service) {
$this->loginService = $service;
}
public function login() {
$this->loginService->performLogin();
}
}
这种方式让代码更灵活。测试时可以换一个模拟的登录服务,生产环境用真实的。就像同一个手机壳,能装不同型号的手机。
安全角度的差异
从安全角度看,类继承容易造成“过度信任”。子类自动获得父类的所有能力,可能带入不必要的权限。比如管理员类继承普通用户类,结果不小心暴露了敏感操作入口。
依赖注入则更可控。每个依赖都是明确传入的,谁用了什么服务一目了然。就像公司门禁系统,每个人只能拿到自己需要的钥匙,不会因为职位高就自动拥有所有房间的权限。
实际开发中,大型项目越来越倾向依赖注入。框架如Spring、Laravel都大力推广这种方式。不是说继承完全不能用,而是要意识到它的隐性成本——耦合度高,修改风险大。
小项目用继承没问题,就像自家修个花架随便用木头钉就行。但要做高楼大厦,就得讲究结构设计,每根梁柱的连接方式都得清晰可控。