最近在重构公司的电子商务网站,其中有个打折消费的功能.这里简单介绍下,比如,网站搞活动买二送一(以下称A),或者买二瓶其中价格低的一瓶半价(以下称B),.
最初的设计是很粗糙的,因为之前网站是没有活动,后来增加一个活动,现在又要增加新的活动.从一开始的直接写代码,到后来的if else 判断打折条件,到现在又要添加新的打折,觉得这样的代码写的很粗糙,有种不爽的感觉.
现在刚好有机会重构这里,就大概设计一下,也好让这里更面向对象一点.之前没有这样设计是因为根本没有想到会有这么多的改变,呵呵,还好可以重构,这个也是不断学习的过程.
好了,废话不说了,贴下设计类图.

之前有考虑使用接口,因为促销A和促销B,都要实现方法OperateShippingCart,但是后来一想,这2次促销方式,其实都可以统称促销方式,也就是说他们是"is-a"的关系,这样的话使用抽象类比较好.定义一个抽象类Sales,促销A和促销B继承他,并重写他的促销方法.
然后使用简单工厂方法,根据不同的要求创建不同的实例,这样也使用了多态的特性.
Sales sale = SaleFactory.CreateSale();
if (sale != null)//如果有促销活动

{
sale.Operate += AddPresent;//这里使用了委托
save = sale.CountShoppingCart(list);

}

这样就抛弃了起初很多if..else..判断不同的促销方式了,要新增加促销方式的话,使其直接继承Sale,然后重写OperateShippingCart就可以了.
下面说下,这里我使用了委托.使用委托是因为,促销方式A和B的功能只是计算打折后的价格,但是要操作购物车,比如购物满2瓶,就要再赠送他1瓶,或者购物满500元,也要送一瓶酒.这里就需要直接操作购物车了.这里我的促销方式是放在另外一个工程里的,并在website里引用了它,当然不能在OperateShippingCart里直接操作购物车,这样就要引用website导致循环引用了.
后来想了下,这个还是使用委托的好.
委托是对函数签名的封装,事件是委托的一种特殊形式.
要使用委托,首先要定义委托,然后定义事件,在class中判断事件如果不为空,则调用事件订阅者的方法.当然要操作购物车是需要传递参数的,给委托传递参数,只要让参数继承自EventArgs就可以了,这里还遇到个问题,就是Sale里定义了委托,但是在子类中并不能调用它,会出现错误,后来百度知,需要在父类中定义一个虚方法调用委托,然后在子类中重写并调用这个方法就搞定了.
public class ShoppingCartEventArgs :EventArgs

{
int prodID;

public int ProdID

{

get
{ return prodID; }

set
{ prodID = value; }
}
int type;

public int Type

{

get
{ return type; }

set
{ type = value; }
}
int quantity;

public int Quantity

{

get
{ return quantity; }

set
{ quantity = value; }
}
}
public abstract class Sales

{
public delegate void OperatShoppingCartEventHandle(object sender, ShoppingCartEventArgs args);

public event OperatShoppingCartEventHandle Operate;


/**//// <summary>
/// 对购物车中的产品进行折扣处理
/// </summary>
/// <param name="list"></param>
/// <returns>返回节省下来的金额</returns>
public abstract decimal CountShoppingCart(List<CShoppingCartItem> list);


/**//// <summary>
/// 调用委托
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public virtual void Event(object sender, ShoppingCartEventArgs args)

{
if (Operate != null)

{
Operate(sender, args);
}

}
public class MNSale : Sales

{

ISale 成员 同样的一瓶买几送几#region ISale 成员 同样的一瓶买几送几

public override decimal CountShoppingCart(List<CShoppingCartItem> list)

{
decimal save = 0;//节省多少钱
try

{
int count = 0;//总有多少瓶

//除掉不是活动的酒
foreach (CShoppingCartItem item in list)

{
if (item.Sale != (int)ProductState.活动酒)

{
list.Remove(item);
}
}

//循环活动产品
foreach (CShoppingCartItem item in list)

{
count = item.Quantity;
PromotionSend promotionSend = PromotionSendService.GetPromotionSendByWhereClip(PromotionSend._.BeginTime <= DateTime.Now && PromotionSend._.EndTime >= DateTime.Now && PromotionSend._.Buy <= count);
if (promotionSend != null)

{
int m = count / promotionSend.Buy;//买2送1
save += m * item.MemberPrice;
//if (Operate != null)//因为委托在父类定义,这里不能判断是否为空,所以不论是否为空只要先把要传递的参数定义好了再说
//{
ShoppingCartEventArgs e=new ShoppingCartEventArgs();
e.ProdID = int.Parse(item.ProductID.Substring(1));
e.Quantity = m;
e.Type = 0;
Event(this, e);
//}
}
}

}

catch
{ }

return save;
}


public override void Event(object sender, ShoppingCartEventArgs args)

{
base.Event(sender, args);
}
#endregion
这里不得不佩服下园子里那些强人,能把文章写的很长很详细而且面面俱到,真是让人学习的楷模.而自己写的文章总觉得拖泥带水,一带而过,呵呵
还要再学习啊,大家共勉
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)