AOP-IoC-OOP-DI 
目录
今天在学 Midway 的时候又遇到了 IoC 等相关的概念,故而总结一下
随着项目越来越复杂,代码越来越多的时候,总是会出现各种需要“重复”的功能,以上概念/技术就是在这些环境下出现的解决办法
面向对象编程 OOP 
改进:从面向过程编程(POP) 变成面向对象编程(OOP)
优点:
- 结构更清晰,可读性高
- 数据更安全,数据不是全局直接能读取到的了
- 代码更少,复用率更高
需求假设:学校系统有学生和老师,他们都用登陆功能,学生可以查看成绩,老师可以设置成绩
C
// 面向过程实现
struct 老师 {
    用户名
    密码
}
struct 学生 {
    用户名
    密码
    成绩
}
// 学生登陆函数
Bool studentLogin( char *username, char *password) {
    // ...
}
// 老师登陆函数
Bool teacherLogin( char *username, char *password) {
    // ...
}
// 学生查看成绩函数
Int studentCheckScore( char *username, char *password) {
    // ...
}
// 老师设置成绩函数
void teacherSetScore( char *username, char *password, Int score ,char *studentName) {
    // ...
}C++
// 面向对象实现
class User {
    public:
    char *username;
    char *password;
    Bool login(String username, String password){
        // ...
    }
}
class Student : public User {
    public:
    Int score;
    virtual Int checkScore() {
        // ...
    }
}
class Teacher : public User {
    public:
    virtual void setScore(Int score, String studentName) {
        // ...
    }
}面向切面编程 AOP 
现在我们添加一些需求:在登陆,查询成绩,设置成绩时,日志记录和权限校验
原来的方案会导致大量重复的日记和检查代码,并且如果修改了检查代码,所有涉及的函数都要修改
c++
bool checkPermission() {
    // ...
}
void log(String str) {
    // ...
}
// 面向对象实现
class User {
    public:
    char *username;
    char *password;
    Bool login(String username, String password){
        if(!checkPermission()) {
            log(err);
        }
        log(str);
        // ...
    }
}
class Student : public User {
    public:
    Int score;
    virtual Int checkScore() {
       if(!checkPermission()) {
            log(err);
        }
        log(str);
        // ...
    }
}
class Teacher : public User {
    public:
    virtual void setScore(Int score, String studentName) {
        if(!checkPermission()) {
            log(err);
        }
        log(str);
        // ...
    }
}C++
// 面向切面编程实现
// 代理类
class UserProxy {
    public:
    User *user;
    bool login(String username, String password){
        if(!checkPermission()) {
            log(err);
        }
        log(str);
        return user->login(username, password);
    }
    bool checkPermission() {
        // ...
    }
    void log(String str) {
        // ...
    }
}
class StudentProxy : public UserProxy {
    public:
    void checkScore() {
    }
}
class TeacherProxy : public UserProxy {
    public:
    void setScore(Int score, String studentName) {
    }
}
// User 类
class User {
    // ...
}
// Student 类
class Student : public User {
    // ...
}
// Teacher 类
class Teacher : public User {
    // ...
}
main(){
    UserProxy *userProxy = new UserProxy(new Student());
}这里我们使用了代理类的方案实现 AOP,业务函数和检查代码分离,结构更清晰
依赖注入 DI 
除了构建代理类,还可以使用依赖注入,更加简单
但是依赖注入的语法在 C++中比较复杂,这里使用 TS 做演示
使用@xxx这种装饰器将检查和日志的函数注入到业务函数上,简介又方便
TypeScript
// 定义日志装饰器
function Log(target: any, methodName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        console.log(`[LOG] 方法 ${methodName} 被调用,参数:`, args);
        return originalMethod.apply(this, args);
    };
    return descriptor;
}
// 定义权限检查装饰器
function CheckPermission(target: any, methodName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        if (!this.checkPermission()) {
            console.error(`[ERROR] 权限不足,无法执行 ${methodName}`);
            return false;
        }
        return originalMethod.apply(this, args);
    };
    return descriptor;
}
// 定义基础用户类
class User {
    username: string;
    password: string;
    constructor(username: string, password: string) {
        this.username = username;
        this.password = password;
    }
    @Log
    @CheckPermission
    login(username: string, password: string): boolean {
        console.log(`[User] ${username} 登录成功`);
        return true;
    }
    checkPermission(): boolean {
        return true; // 在这里可以加入实际的权限检查逻辑
    }
}
// 定义学生类
class Student extends User {
    @Log
    checkScore() {
        console.log(`[Student] ${this.username} 查询了自己的成绩`);
    }
}
// 定义教师类
class Teacher extends User {
    @Log
    setScore(score: number, studentName: string) {
        console.log(`[Teacher] ${this.username} 给 ${studentName} 设定了分数: ${score}`);
    }
}
// 主程序
const student = new Student("Alice", "12345");
student.login("Alice", "12345"); // 自动调用日志 & 权限检查
student.checkScore();
const teacher = new Teacher("Bob", "admin");
teacher.login("Bob", "admin");
teacher.setScore(90, "Alice");Ioc 容器 
IoC(Inversion of Control)是一种设计模式,它允许应用程序通过依赖注入的方式来获取依赖对象,而不是自己创建。
比如我们现在需要使用控制函数来执行操作,以便将这些功能导出到外部,学生和老师的数据从数据库中获取
每次创建事务都需要创建类,并赋值
js
// 事务管理类
class TransactionManager {
    teacher: Teacher;
    student: Student;
    constructor(teacher: String, student: String) {
        this.teacher = new Teacher(teacher);
        this.student = new Student(student);
        // 从数据库获取学生和老师的数据
        this.student.getData();
        this.teacher.getData();
    }
    // 设置分数
    function setScore( score) {
        teacher.setScore(student, score);
    }
    // 请假
    function leave(reason) {
        teacher.leave(student, reason);
    }
    // 开除
    function dismiss() {
        teacher.dismiss(student);
    }
}js
// 使用 IoC 容器
@Injectable()
class Teacher {
    // ...
}
@Injectable()
class Student {
    // ...
}
class TransactionManager {
    @Inject('teacher')
    @Inject('student')
    function setScore(score) {
        teacher.setScore(student, score);
    }
    function leave(reason) {
        teacher.leave(student, reason);
    }
    function dismiss() {
        teacher.dismiss(student);
    }
}IoC 容器的实现这里没有写,在程序加载时,带有@Injectable()装饰器的类会被注册到 IoC 容器中,当需要使用这些类时,可以通过@Inject()装饰器来获取对应的实例,这样就不用手动创建实例了
参考资料 
事实上我觉得参考资料写得比我好理解多了,例子也更合适
