在工作中,我已经投入开发一个传统的enterprice应用程序,由于设计糟糕和不稳定,它仍在生产中并且在过去几个月停滞不前。
所以我们已经开始使用EF5并将一些设计模式/图层应用到我们的应用程序中。
我正在努力理解的是:在我们的案例中,服务层到底应该做些什么?它会过度架构还是会在不增加不必要的复杂性的情况下提供一些好处?
让我们告诉你到目前为止我们得到了什么:
现在在特定情况下,它是关于计算物品的价格 - 通过直接从arcile获得价格或从物品所在的组中获得价格(如果没有指定价格)。它变得更加复杂,因为还有不同的价格表(取决于订单的完整价值),也取决于客户也可以有特价等。
所以我的主要问题是:谁负责获得正确的价格?
我的想法是: 订单必须知道它所包含的项目。另一方面,这些物品必须知道它们的价格是多少,但订单一定不知道如何计算物品的价格,只需要总结它们的成本。
目前代码的异常:
ArticlePrice(POCO,Mappings很快将由Fluid API交换)
[Table("artikeldaten_preise")]
public class ArticlePrice : BaseEntity
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("einheit")]
public int UnitId { get; set; }
[ForeignKey("UnitId")]
public virtual Unit Unit { get; set; }
[Column("preisliste")]
public int PricelistId { get; set; }
[ForeignKey("PricelistId")]
public virtual Pricelist Pricelist { get; set; }
[Column("artikel")]
public int ArticleId { get; set; }
[ForeignKey("ArticleId")]
public virtual Article Article { get; set; }
public PriceInfo PriceInfo { get; set; }
}
物品价格库:
public class ArticlePriceRepository : CarpetFiveRepository
{
public ArticlePriceRepository(CarpetFiveContext context) : base(context) {}
public IEnumerable<ArticlePrice> FindByCriteria(ArticlePriceCriteria criteria)
{
var prices = from price in DbContext.ArticlePrices
where
price.PricelistId == criteria.Pricelist.Id
&& price.ArticleId == criteria.Article.Id
&& price.UnitId == criteria.Unit.Id
&& price.Deleted == false
select price;
return prices.ToList();
}
}
public class ArticlePriceCriteria
{
public Pricelist Pricelist { get; set; }
public Article Article { get; set; }
public Unit Unit { get; set; }
public ArticlePriceCriteria(Pricelist pricelist, Article article, Unit unit)
{
Pricelist = pricelist;
Article = article;
Unit = unit;
}
}
PriceService(确实有令人讨厌的代码味道...... )
public class PriceService
{
private PricelistRepository _pricelistRepository;
private ArticlePriceRepository _articlePriceRepository;
private PriceGroupRepository _priceGroupRepository;
public PriceService(PricelistRepository pricelistRepository, ArticlePriceRepository articlePriceRepository, PriceGroupRepository priceGroupRepository)
{
_pricelistRepository = pricelistRepository;
_articlePriceRepository = articlePriceRepository;
_priceGroupRepository = priceGroupRepository;
}
public double GetByArticle(Article article, Unit unit, double amount = 1, double orderValue = 0, DateTime dateTime = new DateTime())
{
var pricelists = _pricelistRepository.FindByDate(dateTime, orderValue);
var articlePrices = new List<ArticlePrice>();
foreach (var list in pricelists)
articlePrices.AddRange(_articlePriceRepository.FindByCriteria(new ArticlePriceCriteria(list, article, unit)));
double price = 0;
double priceDiff = 0;
foreach (var articlePrice in articlePrices)
{
switch (articlePrice.PriceInfo.Type)
{
case PriceTypes.Absolute:
price = articlePrice.PriceInfo.Price;
break;
case PriceTypes.Difference:
priceDiff = priceDiff + articlePrice.PriceInfo.Price;
break;
}
}
return (price + priceDiff) * amount;
}
public double GetByPriceGroup(PriceGroup priceGroup, Unit unit)
{
throw new NotImplementedException("not implemented yet");
}
//etc. you'll get the point that this approach might be completely WRONG
}
我的最后一个问题是: 如何正确建模我的问题?这是正确的,我正在构建我的代码吗? 我的服务层将如何正确显示?我宁愿拥有ArticlePriceService,ArticleGroupPriceService等吗?但谁会连接这些碎片并计算出正确的价格?那样的,例如具有方法“GetPrice”的OrderItemService的责任是什么?但是再次orderItemService必须知道其他服务..
请尝试向我提供有关架构的可能解决方案,以及哪些对象/层执行什么操作。
如果您需要更多信息,请随时向我提出其他问题!
答案 0 :(得分:0)
您确实提供了一个简单的场景,其中Repository本身就足够了。
你有更多的存储库吗?
您是否希望应用程序增长,并且有更多的存储库在使用?
建议使用抽象数据层的服务层,并使用我所见过的大多数应用程序/示例,并且开销并不大。
当您想从多个不同的存储库中获取数据,然后对数据执行某种聚合/操作时,可能会弹出使用服务的一个原因。
然后,服务层将提供操作逻辑,而服务使用者则不必处理多个不同的存储库
您还应该考虑一种情况,即您可能希望在一个事务中更改多个实体(含义 - 多个存储库),并且只有在所有更新操作成功时才将更改保存到数据库。
这种情况应该意味着使用Unit Of Work Pattern,并且可能会结束使用服务层,以实现正确的单元测试。
答案 1 :(得分:0)
当我开始使用对象和架构时,我的主要问题是为类提供一个好名字。
对我而言,似乎应该调用您的服务&#34; ShopService&#34; (或等同的东西)。然后你的方法GetByArticle,应该是nammed GetPriceByArticle。
为更大的价格更改服务名称的想法会更有意义,并且还会解决其他问题(比如您想知道的OrderPriceService)。
也许你可以问问自己&#34;我的页面或窗口的名称与这项服务有什么关系?&#34;只有一个或多个?如果更多,它们有什么共同之处? 这可以帮助您找到适合您服务的好名称,从而获得满足每个需求的不同方法。
告诉我更多。我很乐意帮忙。