【问题标题】:Designing a class in such a way that it doesn't become a "God object"以不会成为“上帝对象”的方式设计一个类
【发布时间】:2011-02-05 02:11:33
【问题描述】:

我正在设计一个允许我在图形上绘制一些函数的应用程序。每个函数都将从一组点绘制,我将传递给这个图形类。

有不同种类的点,都继承自 MyPoint 类。对于某些点,它只是将它们按原样打印在屏幕上,其他点可以忽略,其他点可以添加,因此与它们相关的某种逻辑可能会变得复杂。

如何实际绘制图形不是这里的主要问题。困扰我的是如何让这个GraphicMaker类不成为所谓的God-Object的代码逻辑。

制作这样的东西很容易:

class GraphicMaker {
    ArrayList<Point> points = new ArrayList<Point>();

    public void AddPoint(Point point) {
        points.add(point);
    }

    public void DoDrawing() {
        foreach (Point point in points) {
            if (point is PointA) {
                //some logic here
            else if (point is PointXYZ) {
                //...etc
            }
        }
    }
}

你会怎么做这样的事情?我有一种感觉,正确的方法是将绘图逻辑放在每个 Point 对象上(因此 Point 的每个子类都知道如何绘制自己),但是会出现两个问题:

  1. 有些点需要知道 GraphicObject 类中存在的所有其他点才能知道如何绘制自己。
  2. 我可以将 Graphic 类中的许多方法/属性公开,这样所有点都可以引用 Graphic 类,并且可以根据需要制作所有逻辑,但这不是一个很大的代价为不想上上帝班买单?

【问题讨论】:

    标签: c# java design-patterns oop god-object


    【解决方案1】:

    我会按照你的建议做,让每个点负责绘制自己,将其他点的数组传递给它:

    interface ICanDraw {
        void Draw(ArrayList<Point> allPoints);
    }
    
    public abstract class Point : ICanDraw {
        ...
    }
    
    public PoniePoint : Point {
        public void Draw(ArrayList<Point> allPoints) {
            // do drawing logic here
        }
    }
    

    对于您的 GraphicMaker:

    public void DoDrawing() {
        foreach (Point point in points) {
            point.Draw(points);
        }
    }
    

    (我的 Java 有点生疏,所以这可能不是 100% 语法正确的 Java,但我认为它传达了我的建议)。

    【讨论】:

    • 啊哈!我没有想过让 GraphicObject 类将点列表作为参数传递给 Point 的 Draw() 方法。这似乎是一个非常好的主意。虽然我仍然不确定在 GraphicObject 类中公开所有可能相关的属性不是最好的,因为将来我的点绘制逻辑可能不仅需要所有点的列表,还需要其他一些东西。如果我通过列表而不是公开属性,我必须向点的 Draw() 方法添加新参数。
    • 这实际上取决于 GraphicsObject 的工作方式,但我认为我宁愿不将它传递给 Draw 方法(我可能错了,它非常符合上下文,我没有完整的上下文)。如果您发现需要 GraphicsObject 可以提供的信息子集以及所有点,我会考虑创建一个类,纯粹是为了传递给 Draw 方法,其中包含点列表和来自 GraphicsObject 的其他内容需要。这保持了单一的可重复性和关注点的分离。但是 - 如果 GraphicsObject 与绘图有关,则将其传入。
    • 看看现有系统以获得灵感。在 Swing 中,每个组件都有自己的paint(),它被传递一个Graphics 对象。 Container/Layout/Component 方法允许某些组件影响其他(包含)组件。但是,我不会将列表传递给 Point's Draw。我将向返回其他点列表的 GraphicsObject 添加一个查询。像某种类型的点,在一定距离内,相同的颜色等。
    【解决方案2】:

    您是正确的,Point 的每个子类都应该有自己的绘图方法来覆盖基点 Point 类中的绘图方法。

    绘图方法应该引用图形对象,该对象应该具有公共方法/属性,用于点绘制方法中需要使用的任何内容,包括点列表,如果这是某些事物之一绘图方法需要。

    您为什么担心在图形类上创建公共方法?一旦代码增长,一些额外的可见方法比一个可以做所有事情的巨大方法更容易混淆。

    【讨论】:

    • 是的,我认为你是对的。拥有一些公共属性/方法绝对是要走的路。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-07
    • 2012-04-03
    • 1970-01-01
    • 2017-12-18
    • 2011-04-30
    • 1970-01-01
    相关资源
    最近更新 更多