什么是依賴
簡單的理解就是,一個(gè)類A用到了另一個(gè)類B,這種使用關(guān)系是具有偶然性的,臨時(shí)性的,非常弱的,但是當(dāng)類B發(fā)生變化時(shí),又會影響到類A。
舉個(gè)例子:

圖1
我們有一個(gè)Customer的Controller,它需要完成對Customer的查找或新增,如果我們用EF進(jìn)行數(shù)據(jù)庫操作的話,CustomerController就會對數(shù)據(jù)庫的Context有一個(gè)依賴的關(guān)系。
顯式依賴與隱式依賴
要解釋這個(gè)的話,還是看代碼比較直接。
[Route("customer")]
public class CustomerController:Controller
{
[HttpPost]
[Route("add")]
public IActionResult Add([FromBody]Model.Customer customer)
{
if(!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var context=new CustomerContext(new DBContextOptions<CustomerContext>{});
var result=context.Customers.SingleOrDefault(c=>c.Phone=customer.Phone);
if(result!=null)
{
return BadRequest(new {code=1001,message="手機(jī)號碼已存在"});
}
context.Customers.Add(customer);
context.SaveChanges();
return Ok();
}
[HttpGet]
[Route("detail")]
public IActionResult Detail(int id)
{
var context=new CustomerContext(new DBContextOptions<CustomerContext>{});
var customer=context.Customers.SingleOrDefault(c=>c.Id=id);
if(result==null)
{
return NotFound();
}
return Json(customer);
}
}
這種代碼編寫方式是隱式依賴。
再來看:
[Route("customer")]
public class CustomerController:Controller
{
private CustomerContext _context;
public CustomerController()
{
_context=new CustomerContext(new DBContextOptions<CustomerContext>{});
}
[HttpPost]
[Route("add")]
public IActionResult Add([FromBody]Model.Customer customer)
{
if(!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var result=_context.Customers.SingleOrDefault(c=>c.Phone=customer.Phone);
if(result!=null)
{
return BadRequest(new {code=1001,message="手機(jī)號碼已存在"});
}
context.Customers.Add(customer);
context.SaveChanges();
return Ok();
}
[HttpGet]
[Route("detail")]
public IActionResult Detail(int id)
{
var customer=_context.Customers.SingleOrDefault(c=>c.Id=id);
if(result==null)
{
return NotFound();
}
return Json(customer);
}
}
這種就是顯式依賴。
依賴倒置
高層業(yè)務(wù)不依賴于低層業(yè)務(wù)的具體實(shí)現(xiàn),而依賴于具體的抽象。上面的UML圖可以修改如下:

圖2
將來,如果不適用EF,而改用其他方式的話,UML圖可改動如下:

圖3
這就實(shí)現(xiàn)了依賴倒置,具體代碼如下:
[Route("customer")]
public class CustomerController:Controller
{
private ICustomerRepository _customerRepository;
public CustomerController()
{
_customerRepository=new EFCustomerRepository(new DBContextOptions<CustomerContext>{});
}
[HttpPost]
[Route("add")]
public IActionResult Add([FromBody]Model.Customer customer)
{
if(!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var result=_customerRepository.GetPhone(customer.Phone);
if(result!=null)
{
return BadRequest(new {code=1001,message="手機(jī)號碼已存在"});
}
_customerRepository.Insert(customer);
return Ok();
}
[HttpGet]
[Route("detail")]
public IActionResult Detail(int id)
{
var customer=_customerRepository.GetById(id);
if(result==null)
{
return NotFound();
}
return Json(customer);
}
}
控制反轉(zhuǎn)
將控制權(quán)交出去,代碼如下:
private ICustomerRepository _customerRepository;
public CustomerController(ICustomerRepository customerRepository)
{
_customerRepository=customerRepository;
}
這樣,你既可以傳EFCustomerRepository,也可以傳MemoryCustomerRepository了。