设计模式 – 良好的OO设计 – 单体设计模式

突然间,我发生了一场OO危机。在过去的几年中,我已经很好地使用了Singleton对象。我在许多地方使用过他们。

例如,在设计一个MVC Java应用程序时,我将创建一个Singleton’SystemRegistry’类来存储模型和查看类(我只在简单的应用程序上工作,并且不需要多个视图)。

当我创建我的模型和查看对象(不是单身,只是普通对象),我会做一些像:

SystemRegistry.getInstance().setModel(model);

在我的控制器类(几乎是不同的GUI项目的事件处理程序)中,我可以访问视图或模型,如下所示:

SystemRegistry.getInstance().getView();

我永远不会在我的应用程序的模型部分中使用SystemRegistry类,但有时会在我的视图中使用它来访问(但很少,如果有的话)修改)模型中的信息。

从我所看到的(特别是Steve Yegge’s article),这似乎是一种很差的设计我的应用程序的方法。任何关于更好地构建我的代码的方法的想法。

另外,我如何设计类,可能与Singleton有关,也可能与Singletons无关,就是使用“Manager-type”类。一个例子是我在C中创建的(非常简单的)基于OpenGL的游戏引擎。

主要的类是GameEngine。存储了一大堆管理器并处理主循环,而不是那些超级类。存储在这个类中的一些管理器是这样的:
ObjectManager,RenderingManager,LightingManager,EventManager(包括输入),HUDManager,FrameRateManager,WindowManager等。可能还有一些。

基本上这些类处理游戏引擎的不同方面。这些名字很简单,所以你应该能够很好地了解如何使用它们。

现在,这是一个可重用的基础,我可以在不同的项目中使用,需要改变理想状态。

在每个新游戏中,我将创建一个GameEngine的实例作为一个类范围的变量(大多数游戏逻辑存储在一个类中),并设置不同的管理器(例如,加载窗口坐标或照明来自文件的详细信息,设置FPS等)。要在ObjectManager中注册一个对象,我将执行以下操作:

Player player = new Player();
gameEngine.getObjectManager().addObject(player);

该对象现在将存储在ObjectManager类中的向量中,并且当GameEngine在每个框架中调用ObjectManager drawObjects()方法时将被绘制。

我可能已经在Singletons的文章之后有一些偏执狂(可能没有足够的时间把我的头围绕着),但是我开始猜测并想知道我设计的GameEngine的方式是否合适(因为缺乏一个更好的词),并没有陷入与Singleton模式共享的同样的陷阱。

对我的帖子的任何评论都将不胜感激。

编辑:谢谢你的答案。我很感激他们如果可能的话,如果有人可以给我一些关于上面发布的两个项目场景的提示,我会很乐意。我如何避免使用单身人士/经理?

第一个,DI是否正确答案?我应该甚至给视图访问模型(这可能是更多的MVC响应)?视图是否可以从实现接口中获益(从而可以插入多个不同的视图)?

在第二种情况下,还可以如何构建应用程序?难道只是使用Manager类而不是更具体的名称?或者,在某些情况下,类可以进一步细分(例如ObjectHolder,ObjectDrawer,ObjectUpdater)?

最佳答案
那你为什么写单身?如果您了解您的单身性炎症出了什么问题,您将会知道今后要注意什么。

你为什么相信一次单身人士是解决任何问题的好方法?因为一本书这么说?不要盲目信任书。书籍需要像其他人一样证明自己的说法。如果我告诉你你的代码看起来好多了,如果你把你的显示器颠倒了,举证责任在我身上。即使我是某种代码神。即使世界上数以百万计的开发商每天都在崇拜我,如果我无法证明这一点,我的建议仍然值得,如果我不能让你走“好的,这是有道理的,我明白你为什么推荐这个,我不能想到一个更好的办法“。

对于某种设计模式书也是如此。所以他们写道:“设计模式很棒”,“单身是一种设计模式,因此也是非常棒的”。所以呢?他们可以证明这个说法(不,他们不能,至少不是在单身的情况下),所以忽略它。

如果有人建议你使用单身人士,逻辑是一样的:这些人是否真的提出了一个很好的论据,为什么这是一个好主意?

如果你自己想出一个理由,今天可以看看它有什么问题吗?你忘记了什么呢?

避免将来犯下太多错误的唯一方法是从你已经做出的错误中学习。单身人士还是经理人?当你第一次了解他们时,你应该注意些什么?或者在以后的时候,当你在你的代码中自由地使用它们时。有什么警告标志,应该让你想知道“这些单身人士真的是正确的道路吗?”作为程序员,你必须相信自己的想法。你必须相信你会做出明智的决定。唯一的办法就是在做出错误的决定时学习。因为我们都做,太多了。我们可以做的最好的事情是确保我们不会重复做出相同的坏决定。

关于经理班,他们的问题是,每个班级都应该有一个责任。 “经理人”的职责是什么?它….呃….管理东西如果您无法定义简明扼要的责任范围,那么该类是错误的。究竟需要管理这些对象?管理它们是什么意思?标准库已经提供了用于存储一组对象的容器类。

那么你需要一些代码,负责绘制存储在那里的所有对象。但是,这不一定是与存储对象相同的对象。

还有什么需要管理?找出这些对象意味着什么“管理”,然后知道你需要做什么类别的管理。这很可能不是一个单一的任务,而是几种不同的责任,应该分成不同的类。

关于单身人士,我不会重复我以前说过的话,所以这是一个link

最后一条建议:

螺丝OOP。真。良好的代码与OOP不同。有时候课堂是一个很好的工具。有时候,他们只是把所有东西都弄乱了,把最简单的代码放在无尽的抽象层次之后。

看看其他范例如果你在C工作,你需要知道通用编程。 STL和Boost是如何利用通用编程编写代码来解决许多比同等的OOP代码更干净,更好和更高效的问题的很好的例子。

无论语言如何,从功能编程中都可以吸取许多宝贵的经验教训。

有时候,简单的老程序编程只是你需要的漂亮和简单的工具。

“好设计”的关键是不要尝试“好的OO设计”。如果你这样做,你就把自己锁定在一个范例里。你也可以尝试找到一个使用锤子建造房子的好办法。我不是说这是不可能的,但如果你也允许自己使用其他工具,那么建立更好的房子有更好的方法。

至于您的编辑:

With the first one, would DI have been the correct response? Should I have even given the view access to the model (this is probably more of an MVC response)? Would the view benefit from implementing an interface (so that multiple different views can be plugged in)?

DI将是避免单身人士的一个选择。但不要忘记老式的低科技选项:只需手动传递对需要了解您的“前”单身的对象的引用。

您的渲染器需要知道游戏对象的列表。 (或者真的吗?也许它只有一个方法需要被赋予对象的列表,也许渲染器类本身不需要它)所以渲染器的构造函数应该被赋予该列表的引用。这真的是所有的。当X需要访问Y时,在函数参数的构造函数中将其引用为Y。与DI相比,这种方法的好处在于,使您的依赖性变得非常明确。您知道渲染器知道可渲染对象的列表,因为您可以看到传递给构造函数的引用。你必须写这个依赖,给你一个很好的机会停下来问“这是必要的”吗?你有消除依赖的动机:这意味着打字更少!

当您使用单身或DI时,您最终得到的许多依赖项是不必要的。这两个工具都可以很好地传播不同模块之间的依赖关系,所以这就是你所做的。然后你最终得到一个设计,你的渲染器知道键盘输入,输入处理程序必须知道如何保存游戏。

DI的另一个可能的缺点是一个简单的技术问题。并不是所有的语言都有很好的DI库可用。一些语言使得几乎不可能编写一个健壮和通用的DI库。

In the second case, how else could one have structured the application? Is the gripe simply the use of Manager classes as opposed to more specific names? Or is it that, in some cases, the classes can be further broken-down (e.g. ObjectHolder, ObjectDrawer, ObjectUpdater)?

是的,我想只是重命名他们是一个好的开始。像上面所说的那样,“管理”你的对象是什么意思?如果我管理这些对象,我期望做什么?
你提到的三个班级听起来像是一个很好的分界线。当然,当你深入设计这些类时,你可能会想知道为什么你甚至需要一个ObjectHolder。标准库容器/集合类不是什么?你需要一个专门的“持有对象”类,或者你可以简单地使用List< GameObject>?

所以我认为你们的选择真的都是同样的事情。如果你可以给班级一个更具体的名字,那么你可能不需要把它拆分成多个较小的类。但是,如果你不能想到一个单一的名字来清楚该类应该做什么,那么它可能需要被分解成多个类。

想象你把代码放在半年之后。当你回到它,你会有任何想法“ObjectManager”类的目的是什么?可能不是,但是你会有一个很好的主意,“ObjectRenderer”是什么。它呈现对象。

转载注明原文:设计模式 – 良好的OO设计 – 单体设计模式 - 代码日志