我正在编写面向对象语言的文档,我想知道哪种类是继承的好例子.
一些常见的例子:
class Person { } class Employee extends Person { }
目前我最喜欢的,但我不喜欢Person-> Employee,因为'Employee'看起来不太有趣.
class Bicycle { } class MountainBike extends Bicycle { }
我在一些Java教程中发现了这一点,但是自行车的属性并不是很明显.
class Animal { } class Bird extends Animal { }
和自行车一样.
class A { } class B extends A { }
太抽象了.主要问题是这样的类需要更抽象的属性和方法.
有没有人有一个简单的类层次结构的更好的例子?
我喜欢Stream
层次结构.这个想法是,任何东西都可以使用流,而不关心,通常是什么样的流,以及独立的子类处理存储不一样(例如NetworkStream
,MemoryStream
和FileStream
在.NET).
如果您对接口感兴趣,那么IEnumerable
在.NET中是一个很好的接口- 您可以迭代任何集合而无需关心底层数据结构.
汽车零件可能很有趣,例如您可能有
class part { OEM Manufacturer Number Description } class Tire extends Part { Speed Rating }
我同意Jon Skeet关于他的溪流的例子.也许它并不完美,但它比这里的大部分例子都有一个优势:
这是现实的
自行车,人或动物,形状或武器不会在实际项目中通过继承来建模.(特别是形状,非常危险,因为它不起作用.)
那是我遗憾的遗憾.它经常被教导为必须用来表达你能找到的每个等级的东西.员工是一个人,对吧?因此Employee类必须从Person类继承.但是一个人也是一个LivingCreature,所以我们最好也有一个这样的课程.LivingCreature也是一个生物,所以我们有另一个类.有机体......随意继续.
我认为,如果有人在某个地方实际上通过解释何时应该使用继承来教导继承,而不仅仅是如何在任何层级上强制它,无论它是否有益.
Streams(或者像ChrisW的例子中的设备)具有它们有意义的优势.您希望能够将所有流处理为相同,无论它们是连接到内存缓冲区,文件还是网络套接字.并且所有硬件设备都有许多共同的行为,这些行为可能会被合理地分解为Device基类.
由于许多原因,Animal类是类继承的经典示例.
首先,有明显的方法来扩展潜在的动物类.您可能会从哺乳动物,鸟类,甲壳动物等子类开始.
某些类,如Mammal,将通过添加相当明显的属性("Warm-Blooded"等)来扩展Animal.
如果用动物继承来说明,那么在开发类层次结构时非常常见的其他更有问题的问题是非常明显的 - 这对于解释的目的来说是一件好事.鸟飞,对吗?好吧,不是所有的鸟......所以,你怎么代表飞行?当然,在线有关于如何解决每个解决方案引入的问题和权衡的经典解决方案和大量讨论信息.
因此,我强烈建议使用"动物"作为例子,因为可用信息和示例丰富.
许多人使用Shapes示例,但实际上这是一个危险的例子.当您直观地确定正方形是矩形的子类时,就会出现问题.
在行为方面,正方形比矩形更有限,破坏了可替代性.例如,我们可以要求一个矩形对象来改变它的高度.如果一个正方形是矩形的子类,那意味着我们应该能够问一个正方形.但是,改变正方形的高度意味着它不再是正方形!当然,我们可以相应地增加宽度,但是当我们要求声明类型矩形的对象(实际上是下面的正方形)来改变其高度时,这不是我们所期望的.
它被称为Liskov替代原则,在进行任何严肃的OO开发时你应该意识到它.
广场是的,当然一个子集的矩形,而不是一个子类.这是面向数据的方法和面向行为的方法之间的区别.
像Jon一样,我更喜欢Streams.即使对非程序员来说,也不难解释它的清晰行为导向,避免形状的反直觉性 - 例子.
如果你进入视频游戏可能是这样的:
class enemy{ Health Posx posy Etc } class orc : extends enemy{ speed Strength etc }
代数表达式的层次结构怎么样?这是一个很好的例子,因为它同时使用了继承和组合:
public interface Expression { int evaluate(); public class Constant implements Expression { private final int value; public Constant(int value) { this.value = value; } @Override public int evaluate() { return this.value; } @Override public String toString() { return String.format(" %d ", this.value); } } public class Negate implements Expression { private final Expression expression; public Negate(Expression expression) { this.expression = expression; } @Override public int evaluate() { return -(this.expression.evaluate()); } @Override public String toString() { return String.format(" -%s ", this.expression); } } public class Exponent implements Expression { private final Expression expression; private final int exponent; public Exponent(Expression expression, int exponent) { this.expression = expression; this.exponent = exponent; } @Override public int evaluate() { return (int) Math.pow(this.expression.evaluate(), this.exponent); } @Override public String toString() { return String.format(" %s ^ %d", this.expression, this.exponent); } } public class Addition implements Expression { private final Expression left; private final Expression right; public Addition(Expression left, Expression right) { this.left = left; this.right = right; } @Override public int evaluate() { return this.left.evaluate() + this.right.evaluate(); } @Override public String toString() { return String.format(" (%s + %s) ", this.left, this.right); } } public class Multiplication implements Expression { private final Expression left; private final Expression right; public Multiplication(Expression left, Expression right) { this.left = left; this.right = right; } @Override public int evaluate() { return this.left.evaluate() * this.right.evaluate(); } @Override public String toString() { return String.format(" (%s * %s) ", this.left, this.right); } } }
然后你可以提供一个激励性的例子,如:
public static void main(String[] args) { Expression two = new Constant(2); Expression four = new Constant(4); Expression negOne = new Negate(new Constant(1)); Expression sumTwoFour = new Addition(two, four); Expression mult = new Multiplication(sumTwoFour, negOne); Expression exp = new Exponent(mult, 2); Expression res = new Addition(exp, new Constant(1)); System.out.println(res + " = " + res.evaluate()); }
哪个会产生:
( ( ( 2 + 4 ) * - 1 ) ^ 2 + 1 ) = 37
我认为Shape是一个很好的抽象类.有2D和3D形状.2D形状通常具有面积,而3D形状具有体积.两者都可以有"位置"或"群众中心".
一些建议:
class Shape {..} class Shape2D extends Shape {...} class Circle extends Shape2D {...} class Rectangle extends Shape2D {...} class Polygon extends Shape2D {...} class Shape3D extends Shape {...} class Sphere extends Shape3D {...}