[ASP.NET 设计模式] 用Visual Studio2010搭建一个简单的分层结构示例Step by Step —— 02 业务逻辑层

注:本例来自图书Professional ASP.NET Design Pattern,该书的亚马逊链接为:http://www.amazon.com/Professional-ASP-NET-Design-Patterns-Millett/dp/0470292784/ref=sr_1_1?ie=UTF8&qid=1296479229&sr=8-1

转载请注明本文来自博客园 http://www.cnblogs.com/charrli

 

业务逻辑层就是将数据的获取和数据的表现同数据的“转换方法"(业务逻辑)分离出来,单独进行建模,成为数据访问层和数据表现层的中间层。这里我们要实现的业务逻辑如前文所说:

假设数据库中有一张名为Product的表:

image

显示在ASPX页面上,该表如下:

image

这里程序试图实现的业务逻辑为:当用户选择不打折(no discount)时,售价Selling Price与数据库相同;当用户选择打折时,SellingPrice为原价95折。如果最终的SellingPrice比RRP建议零售价低,则在Discount里显示折扣了多少,同时在Savings栏里显示折扣比例。如果SellingPrice比RRP价格高或者相等,则Discount和Savings都不显示。

对业务逻辑建模如下:

image

这里Product类是对表Product建模得到,Price代表了表中几个与借个相关的属性。同时表明,Price中有一个field是IDiscountStrategy接口对象。该接口有两个实现,一是NullDiscountStrategy,二是TradeDiscountStrategy。下面介绍对业务逻辑层Business Logic Layer的实现步骤。注意最好是把每个类都使用一个单独的CS文件。

1. 实现IDiscountStrategy接口:

public interface IDiscountStrategy
{
    decimal ApplyExtraDiscountsTo(decimal OriginalSalePrice);
}

这里接口以Strategy命名结尾,表明这里才采用了策略模式Strategy Pattern。所谓策略模式,就是让对象在运行时动态改变自己的算法和行为。在这个例子里,策略模式表现为,对象需要根据客户选择NoDiscount还是TradeDiscount来改变Selling Price的价格。具体实现上,这里使用的方法是,在Price内部有一个接口对象,它可以指向一个NullDiscountStrategy对象,也可以指向一个TradeDiscountStrategy对象,而这两个对象都有自己的不同的价格的实现方法。

2. 实现TradeDiscountStrategy类:

public class TradeDiscountStrategy : IDiscountStrategy
{       
    public decimal ApplyExtraDiscountsTo(decimal OriginalSalePrice)
    {
        decimal price = OriginalSalePrice;           
       
        price = price * 0.95M;           

        return price;
    }    
}

3. 实现NullDiscountStrategy类:

public class NullDiscountStrategy : IDiscountStrategy
{       
    public decimal ApplyExtraDiscountsTo(decimal OriginalSalePrice)
    {
        return OriginalSalePrice;
    }
}

4. 实现Price类:

public class Price
{
    private IDiscountStrategy _discountStrategy = new NullDiscountStrategy();
    private decimal _rrp;
    private decimal _sellingPrice;

    public Price(decimal RRP, decimal SellingPrice)
    {
        _rrp = RRP;
        _sellingPrice = SellingPrice;
    }

    public void SetDiscountStrategyTo(IDiscountStrategy DiscountStrategy)
    {
        _discountStrategy = DiscountStrategy;
    }

    public decimal SellingPrice
    {
        get { return _discountStrategy.ApplyExtraDiscountsTo(_sellingPrice); }
    }

    public decimal RRP
    {
        get { return _rrp; }
    }

    public decimal Discount
    {
        get {
            if (RRP > SellingPrice)
                return (RRP - SellingPrice);
            else
                return 0;}
    }

    public decimal Savings
    {
        get{
            if (RRP > SellingPrice)
                return 1 - (SellingPrice / RRP);
            else
                return 0;}
    }       
}

注意这里Price类将原数据库中的表的两个与价格相关的field全部实现为了Private的field,也就是说外部不能直接访问,如果要访问呢,必须要铜鼓Price类的Property才可以。这样就给程序使用get;set;方法,利用动态的Strategy来对价格进行变换提供了机会。

这里private的RRP和SellingPrice的值只能在构造函数中直接赋值,所以这两个field的值始终与数据库里的相同。

同时注意到SetDiscountStrategy方法,这给外部操作Price类提供了一机会,可以直接修改Property获得的价格的Strategy。

5. 实现Product类:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Price Price { get; set; }
}

6. 实现CustomType枚举类型:

public enum CustomerType
{
    Standard = 0,
    Trade = 1
}

这里Standard代表没有折扣,Trade代表有折扣。

7. 实现DiscountFactory类:

public static class DiscountFactory
{
    public static IDiscountStrategy GetDiscountStrategyFor(CustomerType customerType)
    {
        switch (customerType)
        {
            case CustomerType.Trade:
                return new TradeDiscountStrategy();
            default:
                return new NullDiscountStrategy();
        }
    }
}

这里用到了工厂模式。所谓工厂模式,就是静态类(表明该类即不能继承也不能实例,专为用作使用其内部的静态方法)内部得静态方法,可以利用一个switch结构,根据不同的输入参数,产生不同的对象。

8. 实现IProductRepository接口:

public interface IProductRepository
{
    IList<Product> FindAll();
}

这里用到了仓储模式。所谓仓储模式,就是将数据库中的数据抽象为内存中的代表,从而实现了上层应用与数据库具体内容的分离。

9. 实现ProductListExtensionMethods类:

public static class ProductListExtensionMethods
{
    public static void Apply(this IList<Product> products, IDiscountStrategy discountStrategy)
    {
        foreach (Product p in products)
        {
            p.Price.SetDiscountStrategyTo(discountStrategy);
        }
    }
}

这里使用到了拓展方法。使用拓展方法可以将要对对象使用的方法,变成对象自己拥有的方法。因为如果是要对该对象使用该方法,那么需要一个动作的发出者,但是我们显然不知道谁发出这个动作比较好,所以将这个对对象实施的方法,变成了对象自己拥有的方法。注意这里“对象”不仅仅是指已经由类所定义的对象,还包括IList这样的泛型接口。

 

10. 实现Product Service类:

public class ProductService
{
    private IProductRepository _productRepository;

    public ProductService(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public IList<Product> GetAllProductsFor(CustomerType customerType)
    {
        IDiscountStrategy discountStrategy = DiscountFactory.GetDiscountStrategyFor(customerType);
        IList<Product> products = _productRepository.FindAll();

        products.Apply(discountStrategy);

        return products;
    }   
}

ProductService类的作用就是,根据上层传入的CustomerType,返回本类中定义的Product的集合。

在以上十个文件都完成以后,由于使用了接口实现了层与层之间的断耦,该Project可以独立进行build。

 

[ASP.NET 设计模式] 用Visual Studio2010搭建一个简单的分层结构示例Step by Step —— 01 准备工作
http://www.cnblogs.com/charrli/archive/2011/01/31/1948483.html

[ASP.NET 设计模式] 用Visual Studio2010搭建一个简单的分层结构示例Step by Step —— 02 业务逻辑层
http://www.cnblogs.com/charrli/archive/2011/01/31/1948504.html

[ASP.NET 设计模式] 用Visual Studio2010搭建一个简单的分层结构示例Step by Step —— 03 服务层
http://www.cnblogs.com/charrli/archive/2011/02/01/1948521.html

[ASP.NET 设计模式] 用Visual Studio2010搭建一个简单的分层结构示例Step by Step —— 04 数据访问层
http://www.cnblogs.com/charrli/archive/2011/02/01/1948523.html

[ASP.NET 设计模式] 用Visual Studio2010搭建一个简单的分层结构示例Step by Step —— 05 表现层
http://www.cnblogs.com/charrli/archive/2011/02/01/1948554.html

[ASP.NET 设计模式] 用Visual Studio2010搭建一个简单的分层结构示例Step by Step —— 06 用户界面层
http://www.cnblogs.com/charrli/archive/2011/02/01/1948563.html

posted on 2011-01-31 23:00  李志鹏  阅读(681)  评论(0)    收藏  举报

导航