首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >书店类设计

书店类设计
EN

Code Review用户
提问于 2012-02-09 07:31:42
回答 2查看 796关注 0票数 3

这不是作业。我正在努力学习OOD原则和设计模式自己。

假设我有这样的问题:

书店买卖两种类型的书:

  1. 非技术性的{标题,作者,价格}
  2. 技术{标题,作者,价格,CD}

此外,客户购买一本技术书籍时会得到一张CD。CD对象定义为,CD {Title,Price}。非技术书籍的价格将仅为书的价格.技术书的价格是书和CD的价格之和。创建一个C#程序以显示以下信息:

  • 购书总数&价格: XXX & XXX.XX
  • 图书销售总额及价格: XXX & XXX.XX
  • 技术图书销售总额和价格: XXX & XXX.XX
  • 非技术图书销售总额及价格: XXX & XXX.XX

我设计了这样的程序:

代码语言:javascript
复制
abstract class Publication
{
    public virtual string Title { get; set; }
    public virtual double Price { get; set; }
}

class CD : Publication
{
}

abstract class Book : Publication
{
    public virtual string Author { get; set; }
}

class TechnicalBook : Book
{
    public CD Cd { get; set; }
    public override double Price
    {
        get
        {
            return (base.Price + Cd.Price);
        }
    }
}

class NonTechnicalbook : Book
{
}

abstract class Shop
{
    private IDictionary<string, Book> boughtDictionary;
    private IDictionary<string, Book> soldDictionary;

    public Shop()
    {
        boughtDictionary = new Dictionary<string, Book>();
        soldDictionary = new Dictionary<string, Book>();
    }

    public virtual void Buy(Book item)
    {
        boughtDictionary.Add(item.Title, item);
    }

    public virtual void Sell(string title)
    {
        Book book = boughtDictionary[title];
        boughtDictionary.Remove(book.Title);
        soldDictionary.Add(book.Title, book);
    }

    public virtual int GetBoughtBookCount()
    {
        return boughtDictionary.Count;
    }

    public virtual double GetBoughtBookPrice()
    {
        double price = 0.0;

        foreach (string title in boughtDictionary.Keys)
        {
            price = price + boughtDictionary[title].Price;
        }
    }

    public virtual int GetSoldBookCount()
    {
        return boughtDictionary.Count;
    }

    public virtual double GetSoldBookPrice()
    {
        double price = 0.0;

        foreach (string title in soldDictionary.Keys)
        {
            price = price + soldDictionary[title].Price;
        }
    }

    public virtual double GetTotalBookCount()
    {
        return this.GetBoughtBookCount() + this.GetSoldBookCount();
    }

    public virtual double GetTotalBookPrice()
    {
        return this.GetBoughtBookPrice() + this.GetSoldBookPrice();
    }

    public virtual void Show()
    {
        Console.WriteLine("Total number of books Bought & Price: ", this.GetTotalBookCount() + " & " + this.GetTotalBookPrice());
        Console.WriteLine("Total number of books Sold & Price: ", this.GetSoldBookCount() + " & " + this.GetSoldBookPrice());
    }
}

这种设计是否符合开闭原则?现在我无法理解如何将技术书和非技术书分开。

EN

回答 2

Code Review用户

发布于 2012-02-09 10:39:14

Price中重写TechnicalBook属性会修改Publication的行为。这意味着你破坏了OCP。此外,如果您刚刚将TechnicalBook.Price设置为10.0,您希望它是什么?(当您只覆盖get时,它会编译吗?)

您可以做的是使用模板方法模式:

代码语言:javascript
复制
abstract class Publication
{
    // ...
    public decimal IndividualPrice { get; set; }
    public decimal Price {
        get { return CalculatePrice(); }
    }

    protected decimal CalculatePrice() {
        decimal price = IndividualPrice;
        price += GetAdditionalPrices();
        return price;
    }

    protected virtual decimal GetAdditionalPrices() {
        return 0;
    }
}

public class TechnicalBook : Publication
{
    // ...
    protected override decimal GetAdditionalPrices() {
        return Cd.Price;
    }
}

这使得Publication因修改而关闭(不能更改价格/单个价格),但对扩展开放(可以增加价格)。

(我的示例中的命名和结构可能会得到改进,但它可以达到目的)

不过,这种行为仍然可以修改,因此更好的解决方案是可以添加一些集合或规则集,这样就不会在不调用GetAdditionalPrices的情况下意外地覆盖base.GetAdditionalPrices()

票数 4
EN

Code Review用户

发布于 2012-02-09 10:16:46

我不谈公开-封闭原则,因为我不知道。

如何从NonTechnical图书

中分离技术

第二个问题属于StackOverflow。

还有一个理由为你的每一个真正的问题打开一个单独的问题..。

但你可以这样做:

代码语言:javascript
复制
if(book is TechnicalBook) {
    // ...
} else if(book is NonTechnicalBook) {
    // ...
} else {
    // This is why I would suggest Book class not being abstract...
    // and removing the NonTechnicalBook class, making the TechnicalBook extend Book.
    throw new ArgumentException();
}

对代码

的注释

  1. public CD Cd应该是Cd CdCD CD
  2. 我不认为有NonTechnicalbook的定义有什么好处。如果不是抽象的,你就不能用普通的书吗?,但也许这是您提到的原则的一部分。
  3. IDictionary<string, Book> boughtDictionary;,如果我买两本名为C# for Dummies的书呢?这应该是一个Dictionary<Book, int>
  4. 变量名中的单词dictionary匈牙利符号 --这是我要避免的。
  5. 如果我想卖一本不存在的书呢?卡博姆!

你试过运行你的代码吗?例如:-您的Console.WriteLine()不像您期望的那样工作,您有一个逗号而不是一个加号;-有些方法甚至不返回值,因此不编译;- GetSoldBookCount正在使用boughtDictionary;-等等。

闻起来很像家庭作业。

  1. 其中一些

这感觉真像家庭作业。

修改后的代码建议

(对括号缩进表示抱歉。太麻烦了,不能把它改回你的风格。)

代码语言:javascript
复制
namespace BookSellers
{
    using System.Linq;
    abstract class Publication
    {
        public virtual string Title { get; set; }
        public virtual double Price { get; set; }
    }

    class CD : Publication
    {
    }

    abstract class Book : Publication
    {
        public virtual string Author { get; set; }
    }

    class TechnicalBook : Book
    {
        public CD CD { get; set; }
        public override double Price {
            get {
                return (base.Price + CD.Price);
            }
        }
    }

    class NonTechnicalbook : Book
    {
    }

    abstract class Shop
    {
        private IDictionary<Book, int> BooksInStock;
        private IDictionary<Book, int> BooksSold;

        public Shop() {
            BooksInStock = new Dictionary<Book, int>();
            BooksSold = new Dictionary<Book, int>();
        }

        public virtual void Buy(Book book) {
            int count;
            if (!BooksInStock.TryGetValue(book, out count)) {
                count = 0;
            }
            BooksInStock[book] = count + 1;
        }

        public virtual void Sell(Book book) {
            int count;
            if (!BooksInStock.TryGetValue(book, out count)
                || count < 1
                ) {
                throw new ArgumentException("Book is not in stock.", "book");
            }
            BooksInStock[book] = count - 1;

            if (!BooksSold.TryGetValue(book, out count)) {
                count = 0;
            }
            BooksSold[book] = count + 1;
        }

        public virtual int GetTotalBooksCount() {
            return GetStockCount() + GetSoldBooksCount();
        }
        public virtual int GetStockCount() {
            return BooksInStock.Values.Sum();
        }
        public virtual int GetSoldBooksCount() {
            return BooksSold.Values.Sum();
        }

        public virtual double GetTotalBooksPrice() {
            return GetStockBooksPrice() + GetSoldBooksPrice();
        }
        public virtual double GetStockBooksPrice() {
            return BooksInStock.Sum(pair => pair.Key.Price * pair.Value);
            /* Same as:
            double price = 0.0;
            foreach (var pair in BooksInStock) {
                Book book = pair.Key;
                int count = pair.Value;
                price += book.Price * count;
            }
            return price;*/
        }
        public virtual double GetSoldBooksPrice() {
            return BooksSold.Sum(pair => pair.Key.Price * pair.Value);
        }

        public virtual void Show() {
            Console.WriteLine(string.Format(
                "Total number of books Bought & Price: {0} & {1}",
                GetTotalBooksCount(),
                GetTotalBooksPrice()
                ));
            Console.WriteLine(string.Format(
                "Total number of books Sold & Price: {0} & {1}",
                GetSoldBooksCount(),
                GetSoldBooksPrice()
                ));
        }
    }
}
票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/8797

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档