请考虑以下几点:
public abstract class Item {
String name;
String description;
//concrete getters and setters follow
}
public class InventoryItem extends Item {
//empty subclass of Item
}
public class CartItem extends Item {
int quantity;
int tax;
//getters and setters for quantity and tax follow
}
InventoryItem表示可供销售的商品,而CartItem表示添加到购物车中的商品,因此它具有其他属性,如数量和税收。在这个场景中,抽象类Item的子类可以为空吗?
选项2:我们可以有一个空的Item接口。InventoryItem将实现Item并定义name和description属性,并具有getters和setters。CartItem将从InventoryItem扩展,并将quantity和tax定义为属性,并具有getters和setters。
选项3:有一个Item接口是不是更好?InventoryItem将实现Item。然后,我们可以拥有一个包含“has-an”项和两个属性(即tax和quantity )的CartItem类
发布于 2012-08-03 02:17:01
我认为这种设计没有什么问题:它明确地将Item
指定为基类,并将InventoryItem
/ CartItem
指定为可实例化的类。我将把Item
重命名为AbstractItem
(Java类库就是这么做的),以强调这样一个事实:这个类的预期用途是用作其他类的基础。
有一些特定于C++的问题,比如assignment through the base pointer,使所有“非叶”类成为抽象类是非常可取的。尽管该规则不能从字面上翻译成Java,但我认为让非叶类抽象仍然是一个好主意,即使类是自给自足的。这可以帮助您在用于直接实例化的类和用于扩展的类之间进行显式分离,这对于不熟悉您的代码库的人进行维护是很好的。
更进一步,将所有叶类设置为final
是Java语言中的一种常见做法。这是一个很好的防御规则,特别是当你的类是不可变的时候。
EDIT :就购物车中的建模项目而言,继承不是最佳选择。事实上,我认为这是一件错误的事情。我会让我的CartItem
拥有一个Item
,而不是扩展它,因为项目不会因为被放在购物车中而变成另一种实体。以下是我认为它应该如何建模:
public class Item {
String name;
String description;
...
}
public class CartItem {
Item item;
int quantity;
int tax;
...
}
发布于 2012-08-03 03:27:00
让我提供一个稍微长一点的建议或意见,这可能会提供一些指导。
在设计is--一个层次结构时,我倾向于只通过多态性来区分行为。一般来说,我倾向于避免仅通过数据来区分对象。多年来,我甚至不再为类似于结构的“数据对象”创建继承层次结构,仅仅基于它们所持有的变量。
我花的时间最多的地方是为抽象类表示的方法定义公共接口,然后让子类都服从相同的接口,但具有不同的行为。(Liskov替换原理)
在这种情况下,我会考虑一个公共接口/抽象Item类,其中Item实现的层次结构不同,它们的库存、计算税收等方式不同。我可以有一个.isInCatalog()方法,它可以告诉我item在哪里,或者如果我必须以不同的方式处理它,它的性质是什么,但我仍然会尝试将大多数item类型特定的逻辑封装到它的多态方法的实现中。
虽然这些类型的计算在实践中通常是在数据库的批处理/聚合操作中完成的,而不是在单个对象中完成的,但我会在抽象级别上使用.getTax(),.getQuantity(),然后拥有具有不同行为的子类。(考虑对do进行NullObject重构,以避免处理空值)
在这篇可靠的博客文章中概述了一些有助于这种设计的原则:
http://codebork.com/2009/02/18/solid-principles-ood.html
https://stackoverflow.com/questions/11783091
复制相似问题