以下是什麼問題,以及如何使用面向對象原則更好地實現它?以適當的方式在課堂上設計出現問題
我的應用程序,包含了一些形狀類,所有從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