本系列主要翻译自《ASP.NET MVC Interview Questions and Answers 》- By Shailendra Chauhan,想看英文原版的可访问http://www.dotnettricks.com/free-ebooks自行下载。该书主要分为两部分,ASP.NET MVC 5、ASP.NET WEB API2。本书最大的特点是以面试问答的形式进行展开。通读此书,会帮助你对ASP.NET MVC有更深层次的理解。
由于个人技术水平和英文水平也是有限的,因此错误在所难免,希望大家多多留言指正。
系列导航
Asp.net mvc 知多少(一)
Asp.net mvc 知多少(二)
Asp.net mvc 知多少(三)
Asp.net mvc 知多少(四)
Asp.net mvc 知多少(五)
Asp.net mvc 知多少(六)
Asp.net mvc 知多少(七)
Asp.net mvc 知多少(八)
Asp.net mvc 知多少(九)
Asp.net mvc 知多少(十)
本节主要讲解了依赖注入
Q91. 什么是松耦合以及如何实现松耦合?
Ans. MVC设计模式最重要的功能之一就是关注点分离。
因此,我们的应用程序的模块应该尽可能的保持独立,也就是保持松耦合。它促使更容易的对应用程序进行测试和维护。
通过使用Dependency Injection (DI,依赖注入)可以帮忙我们实现应用程序各个模块之间的松耦合。
Q92. 什么是Dependency Inversion Principle (DIP,依赖倒置原则)和IoC(控制反转)?
Ans. 依赖倒置原则讲的是:
- 高层模块不应该依赖低层模块,它们都应该依赖于抽象。
- 抽象不应该依赖于细节(具体的实现)。但细节应该依赖于抽象。
依赖倒置原则帮助我们开发松耦合的代码,并确保了高层模块依赖于抽象而不是低层模块具体的实现。
控制反转模式是对DIP的一种实现。
IOC指的是一种框架或运行时的编程风格,用来控制程序流程。
IOC意味着我们可以改变常规的控制方式。它在DIP下得以实现。许多基于.net框架的软件开发都使用IOC。
IOC更多的是一个通用术语,不仅仅局限于DI。DI和Service Locator(服务定位器)模式是对IOC模式的一种实现方式。
举例来说,假设你客户端的类需要使用一个Service类组件,那么最佳实践是让你的客户端类知道有个IService接口而不是Service类,这种方式下,你可以随时改变IService的具体实现而不会中断已经部署的代码。
IoC and DIP
DIP是指高层模块不应该依赖低层模块而都应该依赖于抽象。
IOC是用来提供抽象,改变控制。IOC提供了一些方式来实现DIP。如果想让高层模块独立于低层模块,你需要反转控制才能使低层模块不去控制接口并创建对象。 最终IOC提供了控制反转的一些方式。
Q93. 什么是Dependency Injection (DI,依赖注入)?
Ans. DI 是一种软件设计模式,用来允许我们开发松耦合代码。DI是一种很好的方式去减少软件模块之间的紧耦合关心。DI帮助更好的去管理软件中的功能更新和复杂度。DI的目的是让代码可维护。
依赖注入模式使用构造器对对象初始化并提供需要的依赖给对象,也就意味着允许你从类外部注入一个依赖项。
例如,假设你的客户端类需要使用一个服务类组件,那么你能做的就是让你的客户知道一类IService接口而不是服务类。这样,你就可以随时改变Service类的实现而不会中断已经部署的代码。
Q94. 什么是Service Locator(服务定位器)?
Ans. Service Locator 是一种软件设计模式,使得我们可以开发松耦合的代码。
它实现了DIP准则,它很容易与现有代码一起使用使,因为它可以使整体设计变得宽松而不需要强制更改公共的接口。
Service Locator模式引入了一个locator(定位器)的对象,该对象用来解决依赖,意味着通过在类中引用该定位器对象就可以解决类的依赖项。
来看一个具体的实例:
public interface IService {
void Serve();
}
public class Service: IService {
public void Serve() {
Console.WriteLine("Service Called");
//To Do: Some Stuff
}
}
public static class LocateService {
public static IService _Service {
get;
set;
}
public static IService GetService() {
if (_Service == null) _Service = new Service();
return _Service;
}
}
public class Client {
private IService _service;
public Client() {
this._service = LocateService.GetService();
}
public void Start() {
Console.WriteLine("Service Started");
this._service.Serve();
//To Do: Some Stuff
}
}
class Program {
static void Main(string[] args) {
var client = new Client();
client.Start();
Console.ReadKey();
}
}
Q95. 有哪几种方式实现依赖注入?
Ans. 主要有以下三种方式:
** Constructor Injection (构造函数注入)**
这是最常用的注入方式。当实例化类的时候通过给类的构造函数提供依赖项来实现依赖注入。注入的依赖可以在类的任何地方直接使用。适用于类需要一个或多个依赖时。
public interface IService {
void Serve();
}
public class Service: IService {
public void Serve() {
Console.WriteLine("Service Called");
}
}
public class Client {
private IService _service;
public Client(IService service) {
this._service = service;
}
public void Start() {
Console.WriteLine("Service Started");
this._service.Serve();
//To Do: Some Stuff
}
}
//Builder
class Program {
static void Main(string[] args) {
Client client = new Client(new Service());
client.Start();
Console.ReadKey();
}
}
Property Injection(属性注入)
适用于类需要可选的依赖时,或者需要可交换的实现时,比如Log4Net。
在使用时需要Null check。
这种方式不需要增加或修改构造函数。
public class Client {
private IService _service;
public IService Service {
set {
this._service = value;
}
}
public void Start() {
Console.WriteLine("Service Started");
this._service.Serve();
//To Do: Some Stuff
}
}
//Builder
class Program {
static void Main(string[] args) {
Client client = new Client();
client.Service = new Service();
client.Start();
Console.ReadKey();
}
}
Method Injection(方法注入)
这种方式注入依赖到单一的方法,改依赖仅仅被注入的方法使用。
适用于整个类不需要依赖项,而仅仅某个方法需要。
public class Client {
private IService _service;
public void Start(IService service) {
this._service = service;
Console.WriteLine("Service Started");
this._service.Serve();
//To Do: Some Stuff
}
}
//Builder
class Program {
static void Main(string[] args) {
Client client = new Client();
client.Start(new Service());
Console.ReadKey();
}
}
Q96. 依赖注入的好处是什么?
Ans. 主要有以下好处:
- 减少类间耦合
- 增加代码重用
- 提高代码可维护性
- 利于应用程序测试
Q97. 什么是IOC或DI容器?
Ans. IOC和DI描述的是同一个设计模式,通常可以交互使用。
因此有人说IOC容器,有人说DI容器,其实它们都指的是同一个东西,所以不要被术语迷惑。
一个DI容器是一个机制用来创建依赖并当需要依赖的时候自动注入。当需要依赖时它自动基于请求创建对象并注入。DI容器用一种简单容易的方式帮助我们管理应用程序的依赖。
我们也可以不使用DI容器来管理依赖,但是这样我们需要做更多的工作来让其支持可配置和可管理。
Q98. 有哪些流行的DI容器?
Ans. 现在,有很多不错的DI容器适用于.net。
列举如下:
Castle Windsor
- 基于 Castle MicroKernel
- 详细的文档
- 使用者多
- Understands Decorator(理解装饰器)
- Typed factories(类型工厂)
- Commercial support available(官方支持)
Spring.NET
- INTERCEPTION(拦截)
- Comprehensive documentation(全部文档)
- Commercial support available(官方支持)
Autofac
- Easy to learn API(易于学习的API)
- second-generation DI Container(第二代DI容器)
- Commercial support available(官方支持)
Unity
- INTERCEPTION(拦截)
- Good documentation(文档良好)
- Consistent API(一致的API)
Ninject
- Easy to learn API(易于学习的API)
- Second-generation DI Container(第二代DI容器)
Q99.什么是Test Driven Development (TDD,测试驱动开发)?
Ans. TDD是一个开发原则,在写代码之前先写测试。
测试驱动应用程序的设计和开发周期。
在所有的测试通过之前,不能签入代码。
Q100. ASP.NET MVC中有哪些常用的单元测试工具?
Ans. ASP.NET MVC被设计为可测试的,而不需要依赖IIS、数据库或额外的类。
以下是比较流行的测试工具:
• NUnit - NUnit是 Microsoft .NET上比较流行的单元测试框架。它的语法相对简单易用。它提供了跑单元测试的GUI和命令行工具。NUnit提供有NuGet包供下载使用。
• xUnit.NET - xUnit.NET提供了一种自动化运行单元测试的方式。它简单、易于扩展、语法清晰。
• Ninject 2 - Ninject提供连接应用程序中类的方式。
• Moq - Moq提供了一种在测试期间模拟类和接口的机制。