实战剖析三层架构3:不要说BLL没有用

    在本系列的第一篇中,笨熊已经介绍过BLL层的功用,也说明了为什么许多人觉得这一层可有可无。但看近期博客园的文章,还有不少朋友对BLL的存在仍有疑问。正好今天碰到的这个问题颇具代表性,写出来让这些朋友对BLL在业务系统中的功用有个具体的感觉。
    先简要介绍一下要做的功能,在程序中,用户输入商品的商品编码,系统从数据库中提取显示此商品的详细信息(图1)。如果一个商品有多个供应商,则弹出提示框供用户选择某一供应商(图2)。

    图1
实战剖析三层架构3:不要说BLL没有用 [转]_第1张图片

    图2

实战剖析三层架构3:不要说BLL没有用 [转]_第2张图片

功能上来说很简单,先定义一个实体类:


    public class StockTakingCardInfo
    
{
        
private string
 _GoodBarcode;
        
private string
 _GoodBarcodeType;
        
private string
 _GoodCode;
        
private string
 _GoodName;
        
private string
 _Standard;
        
private string
 _Unit;
        
private decimal
 _SellPrice;
        
private string
 _CargoGroup;
        
private string
 _CargoGroupName;
        
private string
 _Distribution;
        
private string
 _DistributionName;
        
private string
 _ProducingArea;

        
public string
 GoodBarcode
        
{
            
get return _GoodBarcode; }

            
set { _GoodBarcode = value; }
        }


        
public string GoodBarcodeType
        
{
            
get return _GoodBarcodeType; }

            
set { _GoodBarcodeType = value; }
        }


        
public string GoodCode
        
{
            
get return _GoodCode; }

            
set { _GoodCode = value; }
        }


        
public string GoodName
        
{
            
get return _GoodName; }

            
set { _GoodName = value; }
        }


        
public string Standard
        
{
            
get return _Standard; }

            
set { _Standard = value; }
        }


        
public string Unit
        
{
            
get return _Unit; }

            
set { _Unit = value; }
        }


        
public decimal SellPrice
        
{
            
get return _SellPrice; }

            
set { _SellPrice = value; }
        }


        
public string CargoGroup
        
{
            
get return _CargoGroup; }

            
set { _CargoGroup = value; }
        }


        
public string CargoGroupName
        
{
            
get return _CargoGroupName; }

            
set { _CargoGroupName = value; }
        }


        
public string Distribution
        
{
            
get return _Distribution; }

            
set { _Distribution = value; }
        }


        
public string DistributionName
        
{
            
get return _DistributionName; }

            
set { _DistributionName = value; }
        }


        
public string ProducingArea
        
{
            
get return _ProducingArea; }

            
set { _ProducingArea = value; }
        }

    }

  然后数据层负责提取数据:  


public IList<StockTakingCardInfo> GetStockTakingCards(string code)    
{
     
/***** 从数据库中提取 *****/

     
string goodCode;

     CmdCommand cmd 
= new
 CmdCommand();
     cmd.CommandText 
= "SELECT DPTM FROM commod_xstm1 WHERE xstm = '" + code + "'"
;
     OleDbDataReader drXstm 
=
 cmd.ExecuteReader();
     
if
 (drXstm.HasRows)
     {   
//输入的是销售条码

          drXstm.Read();
         goodCode 
= drXstm["DPTM"
].ToString();
         drXstm.Close();
     }
     
else

     {   
//输入的是货号
          goodCode = code;
     }
     cmd.Disconnection();

     cmd.CommandText 
= ""
;
     OleDbDataReader dr 
=
 cmd.ExecuteReader();

     IList
<StockTakingCardInfo> stockTakingCards = new List<StockTakingCardInfo>
();
     
if
 (dr.HasRows)
     {   
//
         while
 (dr.Read())
         {
             StockTakingCardInfo stockTakingCard 
= new
 StockTakingCardInfo();
             stockTakingCard.GoodBarcode 
= dr["销售条码"
].ToString();
             stockTakingCard.GoodBarcodeType 
= dr["销售条码类型"
].ToString();
             stockTakingCard.GoodCode 
= dr["商品编码"
].ToString();
             stockTakingCard.GoodName 
= dr["商品名称"
].ToString();
             stockTakingCard.Standard 
= dr["规格"
].ToString();
             stockTakingCard.Unit 
= dr["单位"
].ToString();
             stockTakingCard.SellPrice 
= Convert.ToDecimal(dr["零售价"
]);
             stockTakingCard.CargoGroup 
= dr["柜组"
].ToString(); ;
             stockTakingCard.CargoGroupName 
= dr["柜组名称"
].ToString();
             stockTakingCard.Distribution 
= dr["供货商"
].ToString();
             stockTakingCard.DistributionName 
= dr["供货商名称"
].ToString();
             stockTakingCard.ProducingArea 
= dr["产地"
].ToString();
             stockTakingCards.Add(stockTakingCard);
          }
          dr.Close();
          cmd.Disconnection();
    }
    
return
 stockTakingardings
}

    逻辑层没什么用,直接调用DAL的方法得到数据并返回。

    表现层(这里是WinForm窗体)调用逻辑层方法得到数据,并判断数据条目,如果是一条,则直接显示;如果是多条,则弹出提示框让用户选择,选好后再显示(代码略)。

 

    编写好后运行,代码没有问题,但是在批量测试时发现了几种特殊情况。

    1、一些商品没有提供条码(如蔬菜、水果等散装商品),因此需要根据商品编号生成条码。

    2、一些商品除了本身的条码外,在商品的包装箱上还有条码(比如啤酒、露露、牛奶等,瓶上的条码和箱上的条码是不一样的。因此买一箱时只需扫描包装箱上的条码即可,而不用拆箱扫描里面的商品)。

    3、一些商品只有外包装箱上有条码,商品本身却没有条码,但在销售时还需要拆开来按单个商品销售,这时也要根据商品编码生成条形码。

    考虑这三种情况,那么从数据库中查询时,返回的结果有以下几种(按条码、条码类型、编码、名称、供应商显示,其它列略。条码类型列,A表示条码为商品本身条码,B表示条码为包装箱条码)。

    (1)一般情况(结果返回1 - n条数据)

    692590758024,A,186202,舒尔但莫代尔女单衣,唐山XX有限公司

    (2)商品本身没有条码(结果返回1 - n条数据)

    NULL,NULL,80604,散大米,唐山XX有限公司

    NULL,NULL,80604,散大米,天津市XX加工厂

    (3)商品本身有条码,包装箱还有条码(结果返回n条数据)

    690180818886,A,104992,露露,河北XX股份有限公司

    690180818882,B,104991,露露,河北XX股份有限公司

    690180818886,A,104991,露露,锦江XX有限公司

    690180818882,B,104991,露露,锦江XX有限公司

    (4)商品本身无条码,包装箱有条码(结果返回1 - n条数据)

    692590751824,B,101974,双汇王中王,唐山XX有限公司

    692590751824,B,101974,双汇王中王,河北XX有限公司

    这样汇总整理一下,对于重数据库中查询返回的结果,要做如下处理:首先判断条码是否为空,如果空则生成条码。确认条码不为空后,判断条码类型中是否全是B。如果有A有B,则进行筛选,保留类型为A的条目。如果全是B,则将结果中的条码全部用自动生成条码替换。

 

    确定了处理过程以后,决定需要将此过程放在何处。首先考虑的是数据层,如果能直接提取出所需结果那是最好的,但是有几点原因决定了不能放在数据层:

    (1)数据层的这个方法提供的数据具有通用性,逻辑层中不光一个方法对其进行调用,更改了返回结果会造成逻辑层的其它方法无法使用此结果。

    (2)这个方法的查询语句非常简单,如果增加了此过程,则SQL语句的编写难度会加大,而且很难用1条语句处理这几种情况,必须实现的话,则此方法的SQL查询语句需要改为3句,还要提前执行一条SQL判断语句来决定使用那个SQL查询语句。成倍增加了编写难度与执行时间。

    所以数据层不是进行处理的好地方。 

    再看看表示层,如果放在了表示层,则需要在主窗口(图1)进行判断,对数据进行处理,这样将逻辑处理代码与显示代码混合在一起,不但乱,而且加大了编码量,因为每个逻辑分值里面都要编写相应的显示代码。所以放在表示层也不是个好主意(呵呵,一开始感觉简单,真的想不建逻辑层直接合并在表示层中着)。

    因此,最适合放置此处理过程的地方,就是业务逻辑层了。而且此处的工作就是业务逻辑的处理,即使没有上述问题,也应该放与此层。


public IList<StockTakingCardInfo> GetStockTakingCards(string code)
{      
      IList
<StockTakingCardInfo> stockTakingCards =
 DAL.GetStockTakingCards()

      
/***** 业务逻辑整理(还未编写空白条码处理部分) *****/

      
//判断是否有A码
       bool hasA = false;
      
foreach (StockTakingCardInfo myStockTakingCard in
 stockTakingCards)
      {
          
if (myStockTakingCard.GoodBarcodeType == "A"
)
          {
                hasA 
= true
;
                
break
;
          }
      }

      
//根据是否有A吗处理

       IList<StockTakingCardInfo> reStockTakingCards = new List<StockTakingCardInfo>();
      
if
 (hasA)
      {   
//
          foreach (StockTakingCardInfo reStockTakingCard in
 stockTakingCards)
          {
                
if (reStockTakingCard.GoodBarcodeType == "A"
)
                {
                    reStockTakingCards.Add(reStockTakingCard);
                }
          }
       }
       
else

       {   
//没有A码
             
//将所有的销售条码重新生成

             foreach (StockTakingCardInfo reStockTaking in stockTakingCards)
            {
                
if (reStockTaking.GoodCode.Length == 5
)
                {
                    reStockTaking.GoodBarcode 
= "2000000" +
 reStockTaking.GoodCode;
                }
                
else if (reStockTaking.GoodCode.Length == 6
)
                {
                    reStockTaking.GoodBarcode 
= "200000" +
 reStockTaking.GoodCode;
                }
                reStockTakingCards.Add(reStockTaking);
            }
        }

        
/***** 返回处理后结果 ******/

        
return reStockTakingCards;
}

你可能感兴趣的:(架构)