场景说明
现在有一个订单处理系统,需要我们调整计算价格(价格=产品总价+运费)中“计算运费”的逻辑:
- 在双11的时候,无论订单的金额多少钱,都可以免邮费;
- 在正常情况下订单的金额超过88元时就可以免邮,如果不到88元就需要付12元的快递费。
源代码
namespace _6_3_end
{
public class Program
{
static void Main(string[] args)
{
Order order = new Order
{
Id = 100200,
OrderData = DateTime.Now,
TotalProductPrice = 300,
HasDelivery = false,
};
OrderProcessor orderProcessor = new OrderProcessor();
orderProcessor.Process(order);
Console.Read();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
public int Id { get; set; }
public DateTime OrderData { get; set; }
public decimal TotalProductPrice { get; set; }
public bool HasDelivery { get; set; }//是否发货
public Freight Freight { get; set; }//运费
}
/// <summary>
/// 运费
/// </summary>
public class Freight
{
public decimal Cost { get; set; }
public DateTime DeliveryDate { get; set; }
}
/// <summary>
/// 运费计算
/// </summary>
public class FreightCalculator
{
public decimal CalculateFreight(Order order)
{
if (order.TotalProductPrice <= 88)
{
return 12;
}
return 0;
}
}
/// <summary>
/// 订单处理
/// 专门用来处理订单,我们会在这里计算订单的运费、改变订单的状态。
/// 比如说,订单总金额超过88块,我们就可以给这个用户免运费,否则每次出货都要收取12块钱的运费
/// </summary>
public class OrderProcessor
{
private readonly FreightCalculator _freightCalculator;
public OrderProcessor()
{
_freightCalculator = new FreightCalculator();
}
public void Process(Order order)
{
if (order.HasDelivery)
{
throw new InvalidOperationException("订单已发货");
}
order.Freight = new Freight
{
Cost = _freightCalculator.CalculateFreight(order),
DeliveryDate = DateTime.Today.AddDays(1)
};
order.TotalProductPrice = order.TotalProductPrice + _freightCalculator.CalculateFreight(order);
Console.WriteLine($"订单:{order.Id}已处理完成,总价格为{order.TotalProductPrice}元");
}
}
}
UML
这幅图中两个类的关系,这是订单处理系统和价格计算系统之间的UML关系图
从图中我们可以看到这两个系统之间的依赖关系是has-a
的关系。订单处理系统有一个价格计算系统。如果计算价格方式发生了变化,那么它一定会影响到订单系统,而订单的变化可以又会反应给其他的系统,造成全局性的改变。所以说,订单系统和价格系统目前是一种紧耦合的状态。所以,对于这种has-a
的关系,我们可以选择使用接口来给两个系统解耦。
所以UML中的关系可以改成这样:
使用价格接口来替换价格系统。这样订单系统则会从依赖于一个类转换为依赖于一个接口,而接口的定义,它就是一个简单的声明,不是完整的Class,不包含任何业务逻辑,他的方法也没有代码实现。
至于价格接口的实现,我们完全可以放在一个独立的class中去处理,比如说双十一价格系统、618价格系统、普通价格系统等等,而订单系统可以通过接口来间接使用价格计算的代码实现。
如果未来价格的计算发生了改变,我们只需要在保持价格接口不变的前提下,对现有的实现逻辑进行修改就可以了。我们甚至可以直接给接口换一个新的Class重写实现都没有问题。
对订单来说价格根本就是个黑盒子,订单系统只需要知道什么时候调用价格计算方法就可以了!所以说计算价格的时候调用的底层逻辑是来自Class A 还是 Class B,对于订单来说都不重要,它不知道、也不需要知道计算价格的过程。
所以,通过接口,我们便可以顺利的使订单系统和价格系统形成松耦合的状态。
使用接口改进源代码
- 将
FreightCalculator
class抽离出来作为一个接口:IFreightCalculator
class - 修改
OrderProcessor
class,将原来价格计算变量修改为IFreightCalculator - 修改
FreightCalculator
class:(1)继承IFreightCalculator (2)实现IFreightCalculator ,修改完成后作为正常情况下计算邮费的逻辑 - 添加
DoubleElevenFreightCalculator
class,(1)继承IFreightCalculator (2)实现IFreightCalculator ,可以在双11的情况下使用 - 修改main方法
namespace _6_3_end
{
public class Program
{
static void Main(string[] args)
{
Order order = new Order
{
Id = 100200,
OrderData = DateTime.Now,
TotalProductPrice = 20,
HasDelivery = false,
};
DoubleElevenFreightCalculator doubleEleven = new DoubleElevenFreightCalculator();
OrderProcessor orderProcessor = new OrderProcessor(doubleEleven);
orderProcessor.Process(order);
Console.Read();
}
}
/// <summary>
/// 订单
/// </summary>
public class Order
{
public int Id { get; set; }
public DateTime OrderData { get; set; }
public decimal TotalProductPrice { get; set; }
public bool HasDelivery { get; set; }//是否发货
public Freight Freight { get; set; }//运费
}
/// <summary>
/// 运费
/// </summary>
public class Freight
{
public decimal Cost { get; set; }
public DateTime DeliveryDate { get; set; }
}
/// <summary>
/// 运费计算(正常情况)
/// </summary>
public class FreightCalculator : IFreightCalculator
{
public decimal CalculateFreight(Order order)
{
if (order.TotalProductPrice <= 88)
{
return 12;
}
return 0;
}
}
/// <summary>
/// 订单处理
/// 专门用来处理订单,我们会在这里计算订单的运费、改变订单的状态。
/// 比如说,订单总金额超过88块,我们就可以给这个用户免运费,否则每次出货都要收取12块钱的运费
/// </summary>
public class OrderProcessor
{
//private readonly FreightCalculator _freightCalculator;
private readonly IFreightCalculator _freightCalculator;
//public OrderProcessor()
//{
// _freightCalculator = new FreightCalculator();
//}
public OrderProcessor(IFreightCalculator freightCalculator)
{
_freightCalculator = freightCalculator;
}
public void Process(Order order)
{
if (order.HasDelivery)
{
throw new InvalidOperationException("订单已发货");
}
order.Freight = new Freight
{
Cost = _freightCalculator.CalculateFreight(order),
DeliveryDate = DateTime.Today.AddDays(1)
};
order.TotalProductPrice = order.TotalProductPrice + _freightCalculator.CalculateFreight(order);
Console.WriteLine($"订单:{order.Id}已处理完成,总价格为{order.TotalProductPrice}元");
}
}
public interface IFreightCalculator
{
public decimal CalculateFreight(Order order);
}
/// <summary>
/// 运费计算(双11)
/// </summary>
public class DoubleElevenFreightCalculator : IFreightCalculator
{
public decimal CalculateFreight(Order order)
{
//在双11的时候,无论订单的金额多少钱,都可以免邮费
return 0;
}
}
}
标签:set,get,C#,接口,public,订单,应用,order,freightCalculator
From: https://www.cnblogs.com/ynysj/p/17000476.html