以下是什么问题,以及如何使用面向对象原则更好地实现它?以适当的方式在课堂上设计出现问题
我的应用程序,包含了一些形状类,所有从Shape
继承 - Circle
,Rectangle
,Triangle
等有些需要在屏幕上显示,在这种情况下,他们需要利用普通屏幕的逻辑,所以有包含公共逻辑的ScreenShape
超类,以及ScreenCircle
,ScreenTriangle
子类。
以下是什么问题,以及如何使用面向对象原则更好地实现它?以适当的方式在课堂上设计出现问题
我的应用程序,包含了一些形状类,所有从Shape
继承 - Circle
,Rectangle
,Triangle
等有些需要在屏幕上显示,在这种情况下,他们需要利用普通屏幕的逻辑,所以有包含公共逻辑的ScreenShape
超类,以及ScreenCircle
,ScreenTriangle
子类。
我建议做一个界面形状,它提供关于几何形状的基本蓝图,所有的类实现形状界面,并创建一个单独的类ScreenShape(或抽象类),所有类将扩展并提供在ScreenShape类的屏幕上显示的方法。例如你的矩形类将会有点像这样
class rectangle extends ScreenShape implements Shape
{
// provide implementation of Shape interace methods.
// over-ride ScreenShape methods
public void draw()
{
// actual logic of drawing the objects on screen
}
}
我看到的问题是,您不能从Java中的多个类继承(尽管您可以实现多个接口)。所以你最好将ScreenShape
的功能合并到Shape
中,假设ScreenShape
在其方法中有一些具体的代码。
感谢您的回应,您能否详细说明应该是什么接口以及应该是什么超类? – user1147717 2012-01-18 18:37:49
这种方法的问题是,每个扩展Shape的类现在都具有“屏幕”功能,根据我的理解,这不应该发生。 – 2012-01-18 18:39:08
从最通用到最具体的工作。
所以它应该是这样的:
。形状(包含存在任何种类的“形状”代码 - 说不定一个抽象类或接口)
.. ScreenShape(含有逻辑用于绘制在屏幕上)
...圈(含有逻辑绘制在屏幕上的圆)
...广场(含有逻辑用于绘制在屏幕上为正方形)
所以:
public abstract class Shape {
// ... generic Shape stuff here, possibly an interface
public abstract void getCoordinates();
}
public abstract class ScreenShape extends Shape {
public void drawOnScreen() {
// logic for drawing on a screen here
// likely invoking 'getCoordinates()'
}
}
public class Circle extends ScreenShape {
public void getCoordinates() {
// circle specific stuff here, implementation of stuff inherited from Shape
}
// also inherits whatever 'drawOnScreen()' implementation
// is provided in ScreenShape
}
该解决方案提出了一个新问题:如果我需要一个可以是屏幕形状或普通形状的圆,该如何扩展?我应该做2个新班吗? – Vlad 2013-08-13 12:29:47
您可以实现将实现公共逻辑的draw()方法。
public abstract class Shape{
public void draw(){
//common logic here
drawImpl();
//more logic here if needed
}
public abstract void drawImpl();
}
然后你的实现将实现drawImpl类。
或者,您可以实现一个类ScreenBehaviour并使用组合。然后,每个实现可以使用不同的ScreenBehaviour实现这样的:
public abstract class Shape{
private ScreenBehaviour screenBehaviour;
public final void draw(){
screenBehaviour.execute();
}
}
经理与设计中的问题可能是你正在泄漏问题纳入你的对象模型。你已经混合了形状与渲染的概念。那么现在如果你需要在绘图程序中使用形状呢?根据您目前的设计,你需要定义的PlottedShape
,PlottedCircle
,PlottedSquare
等等等等
您应该保留形状对象层次干净,再定义一个单独的类,它可以处理图形的渲染输出设备。
关于您回应张贴什么@DOC:
@DOK经理不满意......虽然他给了我前进的设计,但仍然他说你应该对这个研究。
我想你的经理并不满足目前的设计的原因是因为它是从一个叫Parallel Inheritance Hierarchiescode smell痛苦。基本上,它描述了你正在经历的事情:每次创建一个新的子类时,你都必须在并行层次结构中创建它的对应子类。 这会让你的设计变得更加困难,从而维持。
当前回答评论
我要评论一些事情,我没有对当前的答案一致。 基本上你建议要么:
ScreenShape
Shape
每个子类绘制逻辑,我可以看到两个问题与选项N°1打算:
Rectangle
等)重新实现它ScreenShape
实现它,因为所有形状都将从它继承。这是不好的,@Perception的答案解释了为什么。XMLShape
类上实现该行为并从中继承,但您已经从ScreenShape
继承。看到问题了吗?选项N°2,迫使你与臃肿的关注呈现您的域模型,再次就像@Perception说:)
一些目标,实现
从前面的,我们可以看到即:
建议的解决方案
首先,让你的Shape
层次清理出来,并留下属于您的问题域的唯一的东西。
然后,您需要不同的方式来显示形状,而无需在Shape
层次结构中实现该行为。如果您不会处理嵌套形状(包含其他形状的形状),则可以使用名为Double Dispatch的技术。它可以让你发送通过编码方法名派往收到这样的论点,即信息基础上,接收器的类型的方法调用:
public class Circle extends Shape {
public void DisplayOn(IShapeDisplay aDisplay) {
aDisplay.DisplayCircle(this);
}
}
public class Rectangle extends Shape {
public void DisplayOn(IShapeDisplay aDisplay) {
aDisplay.DisplayRectangle(this);
}
}
interface IShapeDisplay {
void DisplayCircle(Circle aCircle);
void DisplayRectangle(Rectangle aRectangle);
}
类实现IShapeDisplay
将负责显示各种形状。关于这一点的好处是你设法清除Shape
层级中的那些烦人的细节,并将它们封装在自己的类中。因此,现在您可以在不修改Shape
子类的情况下更改该类。 Refactoring: Improving the Design of Existing Code:
最终意见
有关代码味道和并行继承层次在Martin Fowler的书你可以阅读更多。
此外,如果您需要处理形状嵌套:复合和访问者模式,您想检查Design Patterns: Elements of Reusable Object-Oriented Software书籍。
希望这对你有帮助!
你对这种设计的批评是什么? – DOK 2012-01-18 18:29:45
@DOK经理并不满意......尽管他给了我一个设计方案,但他仍然表示你应该研究这个。 – user1147717 2012-01-18 18:33:22
他有没有说具体的事情?为什么他不满意? – 2012-01-18 18:34:16