之前学习ASP.NET MVC的时候,接触到了Controller的创建过程,其实就是利用IOC来实现,那会对依赖倒置设计模式很模糊,这次学习Attribute 特性 的时候找到了比较详细的相关资料,做个笔记.
官方解释:高层模块不应该依赖底层模块,两者都应该依赖于抽象;抽象不应该依赖细节,细节应该依赖抽象.1)高层模块不应该直接依赖于底层模块的具体实现,而应该依赖于底层的抽象。换言之,模块间的依赖是通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。
2)接口和抽象类不应该依赖于实现类,而实现类依赖接口或抽象类。这一点其实不用多说,很好理解,“面向接口编程”思想正是这点的最好体现。
相比传统的软件设计架构,比如我们常说的经典的三层架构,UI层依赖于BLL层,BLL层依赖于DAL层。由于每一层都是依赖于下层的实现,这样当某一层的结构发生变化时,它的上层就不得不也要发生改变,比如我们DAL里面逻辑发生了变化,可能会导致BLL和UI层都随之发生变化,这种架构是非常荒谬的!好,这个时候如果我们换一种设计思路,高层模块不直接依赖低层的实现,而是依赖于低层模块的抽象,具体表现为我们增加一个IBLL层,里面定义业务逻辑的接口,UI层依赖于IBLL层,BLL层实现IBLL里面的接口,所以具体的业务逻辑则定义在BLL里面,这个时候如果我们BLL里面的逻辑发生变化,只要接口的行为不变,上层UI里面就不用发生任何变化。
在经典的三层里面,高层模块直接依赖低层模块的实现,当我们将高层模块依赖于底层模块的抽象时,就好像依赖“倒置”了。这就是依赖倒置的由来。通过依赖倒置,可以使得架构更加稳定、更加灵活、更好应对需求变化。
上面说了,在三层架构里面增加一个接口层能实现依赖倒置,它的目的就是降低层与层之间的耦合,使得设计更加灵活。从这点上来说,依赖倒置原则也是“松耦合”设计的很好体现。
下面看一段程序:(原文摘自Attribute在.NET编程中的应用(五))
//Inventory.cs
using System;
using System.Collections;
namespace NiwalkerDemo
{
public class Inventory
{
private Hashtable inventory=new Hashtable();
public Inventory()
{
inventory["Item1"]=100;
inventory["Item2"]=200;
}
public bool Checkout(string product, int quantity)
{
int qty=GetQuantity(product);
return qty>=quantity;
}
public int GetQuantity(string product)
{
int qty=0;
if(inventory[product]!=null)
qty = (int)inventory[product];
return qty;
}
public void Update(string product, int quantity)
{
int qty=GetQuantity(product);
inventory[product]=qty-quantity;
}
}
}
//Logbook.cs
using System;
namespace NiwalkerDemo
{
public class Logbook
{
public static void Log(string logData)
{
Console.WriteLine("log:{0}",logData);
}
}
}
//Order.cs
using System;
namespace NiwalkerDemo
{
public class Order
{
private int orderId;
private string product;
private int quantity;
public Order(int orderId)
{
this.orderId=orderId;
}
public void Submit()
{
Inventory inventory=new Inventory(); //创建库存对象
//检查库存
if(inventory.Checkout(product,quantity))
{
Logbook.Log("Order"+orderId+" available");
inventory.Update(product,quantity);
}
else
{
Logbook.Log("Order"+orderId+" unavailable");
SendEmail();
}
}
public string ProductName
{
get{ return product; }
set{ product=value; }
}
public int OrderId
{
get{ return orderId; }
}
public int Quantity
{
get{ return quantity;}
set{ quantity=value; }
}
public void SendEmail()
{
Console.WriteLine("Send email to manager");
}
}
}
下面是调用程序:
//AppMain.cs
using System;
namespace NiwalkerDemo
{
public class AppMain
{
static void Main()
{
Order order1=new Order(100);
order1.ProductName="Item1";
order1.Quantity=150;
order1.Submit();
Order order2=new Order(101);
order2.ProductName="Item2";
order2.Quantity=150;
order2.Submit();
}
}
}
就像原文说的:
程序看上去还不错,商务对象封装了商务规则,运行的结果也符合要求。但是我好像听到你在抱怨了,没有吗?当你的客户的需求改变的时候(客户总是经常改变他们的需求),比如库存检查的规则不是单一的检查产品的数量,还要检查产品是否被预订的多种情况,那么你需要改变Inventory的代码,同时还要修改Order中的代码,我们的例子只是一个简单的商务逻辑,实际的情况比这个要复杂的多。问题在于Order对象同其他的对象之间是紧耦合的,从OOP的观点出发,这样的设计是有问题的,如果你写出这样的程序,至少不会在我的团队里面被Pass.
下面,我们在依赖倒置设计模式的基础上重构代码:
接口部分:
public interface IInventoryHandle
{
bool Checkout(string product, int quantity);
int GetQuantity(string product);
void Update(string product, int quantity);
}
public interface IOrderHandle
{
int orderId { get; set; }
string product { get; set; }
int quantity { get; set; }
void Submit();
void SendEmail();
}
调用部分:
public class Inventory : IInventoryHandle
{
public Hashtable inventory = new Hashtable();
public Inventory()
{
inventory["Item1"] = 100;
inventory["Item2"] = 200;
}
public bool Checkout(string product, int quantity)
{
int qty = GetQuantity(product);
return qty >= quantity;
}
public int GetQuantity(string product)
{
int qty = 0;
if (inventory[product] != null)
qty = (int)inventory[product];
return qty;
}
public void Update(string product, int quantity)
{
int qty = GetQuantity(product);
inventory[product] = qty - quantity;
}
}
public class Logbook
{
public static void Log(string logData)
{
Console.WriteLine("log:{0}", logData);
}
}
public class Order : IOrderHandle,IDisposable
{
public IInventoryHandle _inventory;
public Order(IInventoryHandle inventory, int _orderId)
{
_inventory = inventory;
orderId = _orderId;
}
public void Submit()
{
//检查库存
if (_inventory.Checkout(product, quantity))
{
Logbook.Log("Order" + orderId + " available");
_inventory.Update(product, quantity);
}
else
{
Logbook.Log("Order" +orderId + " unavailable");
SendEmail();
}
}
public void SendEmail()
{
Console.WriteLine("Send email to manager");
}
public int orderId
{
get;
set;
}
public string product
{
get;
set;
}
public int quantity
{
get;
set;
}
public void Dispose()
{
}
}
class Program
{
static void Main(string[] args)
{
var _order1 = new Order(new Inventory(),100);
_order1.product = "Item1";
_order1.quantity = 150;
_order1.Submit();
_order1.Dispose();
var _order2 = new Order(new Inventory(), 250);
_order2.product = "Item2";
_order2.quantity = 150;
_order2.Submit();
_order2.Dispose();
Console.Read();
}
}
参考: http://www.cnblogs.com/landeanfen/p/5169163.html http://blog.csdn.net/niwalker/article/details/8871