项目架构(上)--- MVC\IOC\DI \元组反射\修饰器

news/2025/4/3 8:39:57/文章来源:https://www.cnblogs.com/zhuangdd/p/18802426

这章主要学习:

  • MVC架构
  • IOC控制反转具体思想
  • DI依赖注入的具体实践
  • AOP面向切面和装饰器风格

我们之前学习:

  • express 编写接口
  • mysql  --orm框架 读写数据库

现在,我们需要把他们糅合在一起 实现类似nest.js 或java 的springboot 的框架

 

 MVC 软件架构模式

  1. Model(模型)

    • 职责:表示应用程序的数据和业务逻辑。它负责与数据源(如数据库)进行交互,获取、存储和修改数据。模型独立于用户界面,不直接与用户交互。
    • 示例:在一个在线商店应用中,模型部分可以是代表商品、购物车、用户等的类。
  2. View(视图)

    • 职责:负责显示数据(模型)给用户,并生成用户界面。视图关注数据的展示,但不直接处理数据的变化。视图通常接收来自模型的数据,并将其呈现给用户。
    • 示例:HTML 页面、图形界面组件(按钮、文本框等)以及报表等。
  3. Controller(控制器)

    • 职责:作为模型和视图之间的中介,控制器处理用户的输入并决定如何更新模型和视图。当用户与视图交互时,控制器接收输入、调用模型进行数据处理,并更新视图显示。
    • 示例:在一个在线商店应用中,控制器接收用户的点击操作,比如“添加到购物车”按钮,调用相应的模型方法更新购物车数据,然后更新视图显示。

MVC 架构的工作流程:

  1. 用户交互:用户通过视图与应用程序进行交互(例如点击按钮、提交表单等)。
  2. 控制器处理请求:控制器接收到用户的输入,处理业务逻辑,并根据需要更新模型或视图。
  3. 模型更新:控制器更新模型(如修改数据、查询数据库等)。
  4. 视图更新:模型的变化触发视图更新,视图展示最新的数据给用户。

MVC 的优点:

  1. 分离关注点:将数据(模型)、用户界面(视图)和业务逻辑(控制器)分离,使得各个模块独立,便于开发、维护和扩展。
  2. 可重用性:视图和模型是相互独立的,因此它们可以重用。例如,可以通过不同的视图展示相同的数据。
  3. 易于维护:由于代码模块化,修改一个模块通常不会影响到其他模块,方便代码维护。

应用场景:

MVC 架构广泛应用于 Web 应用程序、桌面应用程序等,尤其适用于用户界面复杂的应用程序。常见的 Web 开发框架如 DjangoRuby on RailsAngularSpring MVC 都基于 MVC 架构。

简而言之,MVC 架构的核心思想是:通过分离模型、视图和控制器来增强代码的模块化、可维护性和可扩展性。

 

 

 

IoC(控制反转)DI(依赖注入)

     是软件开发中的重要概念,特别是在面向对象编程中,它们有助于增强应用程序的模块化、可扩展性和可维护性。虽然这两个概念紧密相关,但它们有不同的定义和作用。

1. IoC(控制反转)

控制反转(Inversion of Control, IoC) 是一种设计原则,它将对象的创建和依赖关系的管理交给框架或外部容器,而不是由对象本身来负责。

通常在传统的编程模型中,类内部会自己管理依赖的创建和控制,比如在类中直接创建其他类的实例。控制反转的核心思想就是“反转”这种控制,把对象的创建和依赖关系管理的控制权交给外部系统(如IoC容器),从而使得类之间的耦合度降低,增强模块的独立性可测试性

IoC的关键特点:

  • 反转控制:通过外部容器(如Spring框架的IoC容器)来控制对象的创建和管理,而不是由对象自己创建依赖对象。
  • 解耦:使得类之间的依赖关系不再由类本身直接管理,减少了代码的耦合性。
  • 增强灵活性:控制反转使得对象更易于替换和扩展,因为它们不直接依赖于特定的实现。

2. DI(依赖注入)

依赖注入(Dependency Injection, DI) 是实现控制反转的一种方式。它是一种设计模式,通过将对象所依赖的其他对象注入到类中,而不是让类自己去创建依赖对象,从而实现依赖关系的反转。

简单来说,依赖注入 就是外部容器(如Spring)将一个对象的依赖关系注入到对象的构造函数、属性或方法中,而不是由对象自己去创建这些依赖。

DI的关键特点:

  • 依赖关系注入:通过外部的IoC容器或框架,自动将所需的依赖项注入到类中。依赖项可以通过构造器注入、属性注入或方法注入的方式传递。
  • 解耦和可测试性:通过依赖注入,可以将业务逻辑与其依赖的组件解耦,使得代码更加易于测试,因为测试时可以替换真实的依赖为模拟对象(mock)或伪对象。

 

IoC与DI的关系

  • IoC是更广泛的概念,它描述了控制反转的整个思想和方法。IoC的实现方式可以有多种,依赖注入(DI)是其中最常见的一种。
  • DI是实现IoC的一种方式。依赖注入是控制反转的具体实现手段之一。通过依赖注入,我们将对象所依赖的组件或服务交给容器管理,并将这些依赖注入到目标对象中,完成反转控制。

 

举例:

1. 构造器注入(Constructor Injection)

   
// Repository 类
class Repository {public getData() {return "Some data from the repository";}
}// Service 类,通过构造器注入 Repository 依赖
class Service {private repository: Repository;constructor(repository: Repository) {this.repository = repository;  // 依赖注入
    }public getServiceData(): string {return this.repository.getData();}
}// 创建 Repository 实例
const repo = new Repository();
// 创建 Service 实例,并注入 Repository
const service = new Service(repo);console.log(service.getServiceData());  // 输出: Some data from the repository

 

2. 属性注入(Property Injection)

3. 方法注入(Method Injection)

class Repository {public getData() {return "Some data from the repository";}
}// Service 类,通过 setter 方法注入 Repository 依赖
class Service {private repository: Repository;public setRepository(repository: Repository) {this.repository = repository;  // 依赖注入
    }public getServiceData(): string {return this.repository.getData();}
}// 创建 Repository 实例
const repo = new Repository();
// 创建 Service 实例
const service = new Service();
// 通过 setter 方法注入 Repository
service.setRepository(repo);console.log(service.getServiceData());  // 输出: Some data from the repository

 

 

 

 

元组数据的反射(Reflection on Tuple Data)

  是指在运行时动态地获取和操作元组数据结构的信息。元组是一种数据结构,它允许你将不同类型的数据组合在一起,但每个元素的位置和类型是固定的。

在TypeScript中,元组的反射可以通过Reflect对象来实现。Reflect是一个内置对象,它提供了一系列静态方法,用于操作对象和元组等数据结构。

以下是一些常用的Reflect方法,用于元组数据的反射:

  1. Reflect.get:获取对象属性的值。
  2. Reflect.set:设置对象属性的值。
  3. Reflect.has:检查对象是否具有某个属性。
  4. Reflect.deleteProperty:删除对象的属性。
  5. Reflect.ownKeys:返回对象自身的属性键。
const tuple = [1, 'hello', true];// 获取元组的第一个元素
const firstElement = Reflect.get(tuple, 0);
console.log(firstElement); // 输出: 1// 设置元组的第二个元素
Reflect.set(tuple, 1, 'world');
console.log(tuple); // 输出: [1, 'world', true]// 检查元组是否包含某个元素
const hasHello = Reflect.has(tuple, 'hello');
console.log(hasHello); // 输出: false// 删除元组的第三个元素
Reflect.deleteProperty(tuple, 2);
console.log(tuple); // 输出: [1, 'world']

 

 

对象修饰器(Object Decorator)

是一个设计模式,常见于面向对象编程中,尤其是在一些现代的编程语言和框架(如 TypeScript、Python、Java 等)中使用。在这种模式下,通过修饰器对现有的对象或类进行扩展、修改或增强其功能,而不需要直接修改对象或类的原始代码。

修饰器模式(Decorator Pattern)

结构型设计模式,它允许你通过将功能附加到对象上来扩展它们,而无需修改对象的结构或直接继承它们。修饰器通常通过包裹(wrap)原始对象来实现对其功能的增强。

基本概念

修饰器主要有两个作用:

  1. 增强对象的功能:在对象的原有功能基础上,增加新的功能或改变原有行为。
  2. 不修改对象本身:使用修饰器来增强对象的功能,而不需要改变对象的类或原始实现。

修饰器的实现

在很多现代编程语言中,修饰器通常以函数或类的形式出现,通过某些方式(如装饰器、函数包装等)修改目标对象的行为。

TypeScript 中的对象修饰器

在 TypeScript 中,修饰器是一个特殊的声明,它能够附加到类、方法、属性或参数上。你可以用它来修改或增强目标对象的行为。TypeScript 支持的修饰器包括 类修饰器方法修饰器访问器修饰器属性修饰器参数修饰器

 

 

1. 类修饰器 (Class Decorator)

类修饰器是一个应用于类构造函数的函数。它们可以用来修改类的定义,添加额外的功能或行为。

function Injectable(constructor: Function) {console.log(`${constructor.name} is Injectable`);
}@Injectable
class MyService {constructor() {console.log("MyService created!");}
}const service = new MyService();

2. 方法修饰器 (Method Decorator)

 

function LogExecutionTime(target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {const start = Date.now();console.log(`Executing ${propertyName}...`);const result = originalMethod.apply(this, args);const end = Date.now();console.log(`Execution of ${propertyName} took ${end - start}ms`);return result;};
}class MyClass {@LogExecutionTimepublic myMethod() {// 模拟一个耗时的操作for (let i = 0; i < 1e6; i++) {}}
}const obj = new MyClass();
obj.myMethod();  // 会打印执行时间

3. 访问器修饰器 (Accessor Decorator)

function LogAccess(target: any, propertyName: string, descriptor: PropertyDescriptor) {const originalGetter = descriptor.get;descriptor.get = function() {console.log(`Accessing ${propertyName}`);return originalGetter?.apply(this);};
}class Person {private _name: string;constructor(name: string) {this._name = name;}@LogAccessget name() {return this._name;}
}const person = new Person("John");
console.log(person.name);  // 会打印 "Accessing name" 然后打印 "John"

4. 属性修饰器 (Property Decorator)

function ReadOnly(target: any, propertyName: string) {let value: any;const getter = () => value;const setter = (newValue: any) => {console.log(`Attempting to modify ${propertyName}...`);};Object.defineProperty(target, propertyName, {get: getter,set: setter,enumerable: true,configurable: true});
}class User {@ReadOnlypublic username: string;constructor(username: string) {this.username = username;}
}const user = new User("admin");
console.log(user.username);  // "admin"
user.username = "newUser";   // 控制台打印 "Attempting to modify username..."

5. 参数修饰器 (Parameter Decorator)

function LogParameter(target: any, methodName: string, parameterIndex: number) {const method = target[methodName];console.log(`Parameter at index ${parameterIndex} in method ${methodName} is being modified.`);
}class MyClass {greet(@LogParameter name: string) {console.log(`Hello, ${name}`);}
}const obj = new MyClass();
obj.greet("Alice");  // 会打印 "Parameter at index 0 in method greet is being modified."

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/908695.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法备案能加急办理吗?

首先明确一点,算法备案官方审核部门是没有所谓的渠道提供快速审核服务的,所有申请者都是一视同仁。其次,我们确实有办法提高审核效率,加快算法备案进度。大家要注意识别所谓的加速办理是哪种情况以下是一些算法备案审核周期的重要信息,供大家参考:一、算法备案官方周期 1…

Windows11+OBS+视频号+麦克风设置直播操作流程

OBS+视频号直播操作流程 一、前期准备 1、可用于直播的电脑,我的是Win11系统 2、硬件设备(相机、采集卡、麦克风等) 3、软件(微信、OBS) 4、虚拟声卡 注:这个教程主要说一下声卡的配置,所以相机和采集卡之类的没有讲到 二、软件安装 微信和OBS这个都不会安装就别折腾了,所…

2025年天梯赛补题记录——整数的持续性

为什么没写出来:哈哈,看到400ms就不想写了,被前面一个题目卡了两次时间心态崩了,头脑发昏以为直接算过去会超时(能说那个时候快困死了脑袋很不灵光吗,给自己的无能找借口嘻嘻) 优化思路: 1.记忆化缓存:一想便知道每个数的分解都算一次很费时间,可以联想到记忆化缓存—…

《上古卷轴3:晨风》——存档技能数据修改

《上古卷轴3:晨风》由于其mod广泛开发,使得游戏的生命力非常强大,至今仍受广大RPG迷的喜爱!但晨风的技能数据如果用CE去修改,则是无用的。这里提供了技能数据的存档顺序,因此可以利用hex editor类的软件直接修改存档CE修改失效 《上古卷轴3:晨风》由于其mod广泛开发,使…

记录一次Armbian安装宝塔面板遇到ModuleNotFoundError: No module named _sqlite3的问题

如果在用Armbian安装宝塔面板的时候遇到ModuleNotFoundError: No module named _sqlite3报错,并且无法进入web面板界面,可以尝试以下操作。报错界面展示:步骤1:更换或添加Ubuntu软件源地址到/etc/apt/source.list.d文件夹的文件中 例如:将下面的地址添加到/etc/apt/source…

Cesium中glb模型颜色暗淡解决

问题: 3dmax导出fbx,此fbx文件导入blender中,再由blender导出成glb模型,该glb模型放入cesium中贴图颜色颜色暗沉无光,试了各种办法(泛光、时差、多光源、唯一光)效果均不明显。 原因: 发现,转格式过程中不知道哪一环出错,会导致模型材质一个叫metallicFactor的属性格…

工业相机与采集卡配套方案:构建高性能机器视觉系统的核心要素

机器视觉技术作为人工智能和智能制造的关键组成部分,正日益广泛地应用于工业自动化、质量检测、机器人引导等领域。而一套高性能的机器视觉系统,离不开工业相机和采集卡的完美配合。工业相机负责图像的采集,采集卡则负责将相机采集到的图像数据传输到计算机进行分析和处理。…

在Linux环境下搭建Dify

在Linux环境下搭建Dify Dify的概述 Dify是一款开源的大语言模型(LLM)应用开发平台。它融合了后端即服务(Backend as Service)和LLMOps的理念,使开发者可以快速搭建生成级的生成式AI应用。即使你是非技术人员,也能参与到AI应用的定义和数据运营过程中。由于Dify内置了构建LLM应…

Linux密钥认证及Windows使用密钥连接Linux

概述 Linux中我们要连接主机,输入用户名密码然后连接,我们发现每次连接都要输入密码,对于一些批量操作不方便 我们需要一种新的认证方式,每次连接不需要输入密码,这个方法就叫密钥认证 密钥认证原理原理详解:使用ssh-keygen命令生成私钥和公钥。 使用ssh-copy-id命令将公…

3.31 等价关系与划分

1 等价关系与划分 1.1 等价关系 若R是自反的,对称的和传递的,则称R为A上的等价关系(和恒等关系、全域关系不同) *关系内部的元素是等价的 *R^2={(a,b)}即第一分量到第二分量有一个长度为2的路径 所以R^2(长度为2的路径)∈R(长度为1的路径),即可判断R具有传递性 1.2 等…