Limitations in subclasses OOP
在爪哇,什么是围绕子类来设计超类的功能的好方法?
例如,考虑类"man",它具有"see"功能,子类"blindman",它不应该具有该功能,但应该具有"man"所具有的所有其他功能。
我能想到的唯一解决方案是有一个抽象类"man",以及两个子类"seeingman"和"blindman",其中seeinman添加了一个函数"see"。
然而,这个解决方案的问题是,如果我现在想添加一个"deafman"类,它扩展了什么?SeeingMan?如果那个人又聋又瞎怎么办?
我认为在这种情况下,您应该使用组合而不是继承,或者拥有组成人类的各种子类。
虽然我确实理解您的逻辑,但基类是一个契约,它保证该类型的所有类都应遵守此行为,具有移除父方法的子类是一个很大的禁忌。
虽然您可以抛出各种异常,但我根本不会沿着这条路走。这样想吧,假设我是一个只需要访问人类对象的开发人员,我期望有某种行为,突然我调用了一个接口方法并得到了一个异常,仅仅因为我调用了它??您不应该知道派生类实现,以及何时可以或不能调用它们。
以下是一些解决方案:
使人类成为基本功能、视觉系统等的组成部分,那么盲人就只有少数功能。
1 2 3 4 5 6 7 8 | class Human { private BasicHumanFunctions _basicFunctions; //contains breathe funcitonality. private VisionSystem _vision; //contains see } class BlindMan { private BasicHumanFunctions _basicFunctions; } |
使人类的基本类只包含所有人都想呼吸的相同行为等,然后创造出一个健康人和一个盲人等,每个人都创造自己的方法。然后,如果需要,您可以进一步使用HealthHuman和子类。
1 2 3 4 5 6 7 8 9 10 11 12 13 | class Human { void breathe() {}; // other Human basic functions; } class HealthyHuman extends Human { void see() {}; //other healthy human functions } class BlindHuman extends Human { void useCane() {}; } |
对于第二种情况,您仍然可以使用组合来共享行为:
1 2 3 4 | class BlindHuman extends Human { private VoiceSubsystem _voice = new VoiceSybsystem(); void speaker() { _voice.speaker();} } |
最重要的原则,是李斯科夫的替代原则。
一旦你得到并应用了它,你就可以建立你想要的模型。
例如,你可以说一个盲人仍然能看到,只有他才能看到黑色(或灰色)的照片。还有一个问题就是法律上的盲人,如果你的照片模糊不清或者部分模糊,你还想看到一些东西。
也可以说,对象可以执行的操作是看不到的。我们要做的是观察。观看是观看的(成功)结果。即使用工作的眼睛,你也可以看不到任何东西!而盲人仍然可以通过聆听(从而听觉,并建立一个精神上的"画面")来"看到"没有眼睛或没有功能的眼睛的东西。
所以,忘记"看"和"听"。用手表听。别指望会有什么结果。(广泛的前提条件)。
转到接口。
为具有公共属性的
例子:
1 2 3 4 5 6 7 8 9 | public class SpecificMan extends CommonMan implements specifiManInter { //methods of CommonMan //Methods of SpecificMan } |
平民阶级:
1 2 3 4 5 | public class CommonMan implements CommonManInter { //methods of CommonMan } |
多莉有权赞成组合而不是继承。你的问题和飞鱼的问题差不多。在这个例子中,我们应该如何处理一个能飞行和游泳的生物?
将飞鱼放入继承层次会很难。不要试图做到这一点,而是使用组合的力量:
现在,每个具体的类都可以指定它们的行为。这是一个合适的地方,基于信息专家的原则:信息专家将把责任放在课堂上,让学生掌握完成任务所需的大部分信息。
注:很难理解上述截图的优点,因此,这里再次说明:
效益-优先考虑对象组合而不是继承-强制开发人员在对行为进行编码时做出有意识的决定(而不是在开发人员必须记住重写的基类中创建默认实现)。-通过抽象不同的行为,它现在可供其他客户机使用。-更松散地耦合意味着更容易坚持开放/关闭原则,在该原则中,代码应该开放以进行扩展,但关闭以进行修改。
For example, consider the class"Man", that has the function"See" and
the subclass"BlindMan" that shouldn't have that function
你不能完全理解。盲人有"看"的功能,它什么也不做(因为传感器和适当的大脑部分之间没有联系,或者传感器不工作(返回空像素列表或0大小的图像)。
一个很好的类比:一个
1 2 3 4 5 | /** * Flush the stream. */ public void flush() { } |
嗯,没什么。没有什么可以冲洗的。好吧,但是为什么
1 2 |
这并不完美,但代码适用于所有类型的作者,甚至那些与
但是,等等,即使对于seeing man函数
让人类按自己的方式做事,给他任务,而不是命令。
看是某种活动的一部分,所以让他独立地使用看(或不使用)。
告诉他去什么地方旅行。健康的人会使用视力,盲人会使用其他感官,而且效率会降低(除非它完全处于黑暗中)。
如果给定任务需要视力(如守卫塔上的警卫),你需要询问他们的视力有多好(没有视力不好的盲人)。
有时你想问他们看到了什么(而不在乎他们听到了什么等等),然后只要求和期望盲人(和其他视障人士)什么也看不见。
如果您希望人类成为被动对象,而其他一些对象处理它们,一个尚未提到的方法是:看看在游戏编程中使用的实体组件编程。它基本上是以一般的方式使用合成。实体只保存身份,组件保存关于实体某些方面的数据(例如视觉可能是屈光度的数量或一些更有用的统计),以及系统处理具有给定系统所需组件组合的实体集。瞄准系统可能需要瞄准组件,并创建包含当前实体当前看到的内容的组件组件组件。其他系统可以合并所有感官的结果,并使用它来执行一些有用的操作。
In java, what is a good way to design around a subclass that reduces the functionality of the superclass?
这基本上是问"继承如何减少功能?"这是Java中我可以想到的一个例子,是集合y[unMuffyBelelist]方法,它表示:
Returns an unmodifiable view of the specified list. This method allows modules to provide users with"read-only" access to internal lists. Query operations on the returned list"read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
所以当我想要删除某个特定的特性时,我会这么做。但是,要确保它的用法是明确的,例如在
但是,如果您希望"减少"多个特性(可能是独立的),并随时间改变它们,我宁愿使用变量而不是继承。最后,您没有扩展超类,那么为什么要为此滥用继承呢?你拥有的是一个具有不同性质的人。
需要记录方法的行为。我可以为您的用例考虑以下类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class Human { private boolean seeing; public void setSeeing(boolean seeing) { ...} public boolean isSeeing() { ... } /** * Returns what the human sees at the moment, or null * if he/she can't see (seeing is false). */ public String see() { if(seeing){ return"I can see a tree!"; }else{ return null; } } // same goes for hearing } |
你可以用布尔值
例如:IsSeeing())
在函数中,可以在if else语句中使用它
在班上,人加上默认情况下是正确的
要实现功能,请使用接口。
要扩展或重新定义功能,请通过扩展基类来使用子类。
如果要在运行时动态添加行为,请实现decorator模式。
相关SE岗位:
实现vs扩展:何时使用?有什么区别?
什么时候使用装饰图案?
像这样的怎么样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class Man { Ears ears; Eyes eyes; } public class Eyes { public boolean canSee() } public class Ears { public boolean canListen() } |
那么逻辑应该是……
1 2 3 4 5 6 7 8 9 10 11 12 | if(man.getEyes().canSee()){ //not blind } else { //blind logic } if(man.getEars().canListen()) { //Not Deaf } |
接口:
我将通过接口定义行为(blindman和seeingman),只公开定义类型(blindman和seeingman)的调用。您不应该真正关心下面的实际实例类型。
抽象父类:
现在,您可以将这些接口与具有所有默认行为的"父"抽象类(包括盲人和视力,如果您也选择)结合起来。
两者结合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public interface BlindMan { public void useBlindStick(); } public interface SeeingMan { public void see(); } public abstract class Man { public void useBlindStick() { //work } public void see() { //work } } public class SomeBlindMan extends Man implements BlindMan { //bla bla } public class SeeingMan extends Man implements SeeingMan { //bla bla } |
希望它有帮助
如果不希望调用函数,可以抛出异常。
例如,在您的场景中:
这样地:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public interface Man { public Object see() throws InabilityException; public Object hear() throws InabilityException; } public class BlindMan implements Man { public Object see() throws InabilityException { throw new InabilityException("blind people don't see"); } public Object hear() { return"what I hear"; } } |
对迪夫曼来说,反之亦然。
如果人是一个以东人而不是一个以东人,同样的事情也会发生。
如果