The*_*ess 5 design-patterns point-of-sale
我是一名软件开发人员 I,他开始像软件开发人员 II 一样思考。作为面试的一部分,我的任务是使用一个相对简单的用例进行编码挑战:构建超市定价系统。
规则和要求:Super Foods 的每件商品都由唯一的四位数代码标识。今天,Super Foods 的定价方案使用以下定价类别,但要注意:价格在不断变化,销售部门总是在创造新的激励措施和优惠,例如买一送一。
EG:薯条和莎莎酱(#6732 和#4900)一起售价 4.99 美元,但单独售价分别为 2.49 美元和 3.49 美元。
EG2:买两支牙刷,每支 1.99 美元,送一支。
EG3:一瓶葡萄酒(货号 #0923)售价 15.49 美元,需额外缴纳 9.25% 的税
通读了设计模式后,这看起来很自然地适合某种形式的Decorator
模式来汇总对象的销售额。带有模式的 SQLite 数据库<ID, ObjectName, Price>
也会以某种方式有用,尽管我对如何在所有这些中创建数据访问对象感到生疏。
我试图用全栈 MVC 的心态来解决这个问题,我觉得我可能对某些事情生疏了。这就是 Spring 框架的著名之处吗?也许可以为这个用例推荐一个更好的 API?
感谢任何人帮助我集思广益地设计这个系统。
装饰器模式用于添加/修改现有类的行为而不更改类本身。因此,它充当现有类的包装器,因此您可能会想到它。重点是你没有要扩展的系统,你是从头开始构建它!
软件设计非常困难,不可能一次性完成。另外,我确信您的潜在雇主对您的设计方式更感兴趣,而不是您使用的技术堆栈。所以我不会对此发表评论。这是你的决定。
根据您的要求,这些是我的初步想法。还有改进的空间(是的!)但至少这应该适用于您的任务范围。这是C#。但这不应该阻止你理解它。
namespace Entities {
public class StoreItem
{
// Code
// Name
// Cost
// Tax -> for specific items
// MfgDate
// ExpDate
}
public class StoreDeal
{
// Code
// Name
// Cost
// Validity
// Items (type: IList<StoreItem>) -> items participating in a deal
}
}
namespace Domain {
public class Cart
{
// Items (type: IList<CartItem>)
// TotalAmount
// TotalDiscount
// FinalAmount
}
public class CartItem
{
public CartItem(string code) {
Code = code; // assume "6732" -> Chips
}
public CartItem(StoreItem item) {
MapStoreItem(item);
}
// declare props: Code, Name, Quantity, Cost
public void Prepare() {
if(Quantity > 0) {
// Invalid operation alert and return
// This is one time call per item type
}
// Sample. Retrieve item from database.
var item = new StoreItem { Code = code, Name = "Chips", Cost = 2.49, Tax = 0 /* etc */ }
MapStoreItem(item);
Quantity = 1;
}
public void UpdateQuantity(int quantity) {
Quantity = quantity;
Cost = Cost * Quantity;
}
private void MapStoreItem(StoreItem item) {
Code = item.Code;
Name = item.Name;
Cost = CalculateCost(item.Cost, item.Tax);
}
private static double CalculateCost(double cost, double tax) {
// If tax > 0, apply it to cost
// else return cost as is
}
}
}
public class DealService
{
public StoreDeal GetDeal(string itemCode) {
// Assume item to be Chips. Retrieve current deal that involve Chips.
// Sample data. You should delegate this stuff to data access layer.
return
new StoreDeal {
Code = "CS4.99",
Name = "Chips and salsa @ $4.99",
Cost = 4.99,
Items = new List<StoreItem> {
new StoreItem { Code = "6732", Name = "Chips" },
new StoreItem { Code = "4900", Name = "Salsa" }
}
}
}
}
public class CartService
{
private Cart cart;
private DealService dealService;
// ctor - inject dependencies
public CartService(Cart cart, DealService dealService) {
this.cart = cart;
this.dealService = dealService;
}
public void AddItem(CartItem item) {
var found = cart.Items.Find(i => i.Code == item.Code);
if (found != null) { // Update quantity
found.UpdateQuantity(found.Quantity + 1);
}
else { // Add new item
item.Prepare();
cart.Items.Add(item);
}
}
public void RemoveItem(string code) {
var found = cart.Items.Find(i => i.Code)
if (found != null) {
cart.Items.Remove(found);
}
}
public void CalculateTotal() {
// Used for checking which items in cart have got deal applied on.
// We don't want "CS4.99" deal applied to both Chips and Salsa, for ex. Only for one of them.
// So this collection simply holds deal codes already applied.
var dealsApplied = new List<string>();
foreach(var item in cart.Items) {
// Check deal
StoreDeal deal = dealService.GetDeal(item.Code);
// Apply the logic for TotalAmount, TotalDiscount, FinalAmount
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您要真正设计这样的系统,那么将会有比上面更多的类。例如,在实际情况中,“Chips”不是一个项目,它是一种项目,因此不能有代码。然而,“Lays Potato Chips”将是“Chips”类型的单个项目,具有自己的代码。此外,StoreItem 将成为抽象实体,该实体由 EdibleItem、PersonalCareItem、HealthCareItem、CosmeticItem 等类型派生,以及真实商店中存在的任何内容,其中 EdibleItem 将专门具有不适用于此列表中其他内容的营养信息。
最后,我只是写了这个(不完整的)代码,没有测试它!你看到评论的地方代码不完整,这是故意的,因为我不想让你盲目地在面试中作弊。:)
归档时间: |
|
查看次数: |
4721 次 |
最近记录: |