NRa*_*Raf 19 singleton design-patterns
突然间,我有一点OO危机.在过去的几年里,我已经很好地利用了Singleton对象.我在很多地方使用它们.
例如,在设计MVC Java应用程序时,我创建了一个Singleton'SystemRegistry'类来存储模型和视图类(我只处理过简单的应用程序,并且不需要多个视图).
当我创建我的模型并查看对象(不是单例,只是普通对象)时,我会做类似的事情:
SystemRegistry.getInstance().setModel(model);
Run Code Online (Sandbox Code Playgroud)
在我的控制器类(几乎是不同GUI项的事件处理程序)中,我可以访问视图或模型,如下所示:
SystemRegistry.getInstance().getView();
Run Code Online (Sandbox Code Playgroud)
我永远不会在我的应用程序的模型部分中使用SystemRegistry类,但有时会在我的视图中使用它来访问(但很少,如果有的话,修改)模型中的信息.
从我读过的内容(特别是Steve Yegge的文章)来看,这似乎是设计我的应用程序的一种糟糕方式.关于更好地构建代码的方法的任何想法.
此外,我设计类的另一个方面是使用'经理类型'类,这些类可能与单身人士有关,也可能与单身人士无关.一个例子是我用C++创建的(非常简单的)基于OpenGL的游戏引擎.
主要的课程是GameEngine.正是过度激励的类存储了一堆经理并处理了主循环而没有.存储在这个类中的一些管理器是:ObjectManager,RenderingManager,LightingManager,EventManager(包括输入),HUDManager,FrameRateManager,WindowManager等.可能还有一些.
基本上这些类处理游戏引擎的不同方面.名称非常简单,因此您应该能够很好地了解它们的使用方式.
现在,这应该是一个可重用的基础,我可以在不同的项目中使用,需要理想地改变它.
在每个新游戏中,我将创建一个GameEngine实例作为一个类范围的变量(大多数游戏逻辑存储在一个类中)并设置不同的管理器(例如,加载窗口坐标或照明文件中的详细信息,设置FPS等).要在ObjectManager中注册一个对象,我会做类似的事情:
Player player = new Player();
gameEngine.getObjectManager().addObject(player);
Run Code Online (Sandbox Code Playgroud)
此对象现在将存储在ObjectManager类的向量中,并在GameEngine在每个帧中调用ObjectManager drawObjects()方法时绘制.
在关于Singletons的文章之后我可能会有点偏执(可能没有足够的时间来绕过它),但我开始猜测并且想知道我设计GameEngine的方式是否合适(由于缺乏一个更好的词而且并没有陷入单身人士模式所共有的陷阱.
对我的帖子的任何评论将不胜感激.
编辑:谢谢你的回答.我非常感激他们.如果可能的话,如果有人能给我一些关于上面发布的两个项目方案的提示,我会很高兴.我怎么能避免使用单身人士/经理?
对于第一个,DI会得到正确的答案吗?我是否应该给视图访问模型(这可能更像是一个MVC响应)?该视图是否会受益于实现接口(以便可以插入多个不同的视图)?
在第二种情况下,如何构建应用程序?抱怨只是使用经理类而不是更具体的名称?或者是,在某些情况下,类可以进一步细分(例如ObjectHolder,ObjectDrawer,ObjectUpdater)?
jal*_*alf 11
好吧,你为什么要写单身人士?如果你了解你的单胎炎出了什么问题,你知道将来要注意什么.
你为什么相信单身人士能解决任何问题呢?因为一本书这么说吗?不要盲目信任书籍.书籍需要像其他人一样证明自己的主张.如果我告诉你,如果你将显示器颠倒过来,你的代码看起来会好得多,那么举证责任就在我身上.即使我是某种代码神.即使全世界数以百万计的开发者每天都崇拜我,如果我无法证明这一点,我的建议仍然没有价值,如果我不能让你"好,那就有道理.我明白为什么你推荐这个,并且我想不出更好的办法".
对于某种设计模式书也是如此.所以他们写道"设计模式很棒","单身是一种设计模式,因此它也很棒".所以呢?他们能证明这种主张是合理的吗(不,他们不能,至少不是单身案例),所以请忽略它.
如果有人建议你使用单身人士,那么逻辑也是一样的:这些人真的提出了一个很好的论据,为什么这是一个好主意?
如果你自己想出一个理由,今天能否看到它出了什么问题?你忘了考虑什么?
避免将来犯太多错误的唯一方法就是从你已经犯过的错误中吸取教训.单身人士或经理人班级如何通过你的防御措施?当你第一次了解它们时,你应该注意什么?或者就此而言,稍后,当您在代码中大量使用它们时.什么警告标志应该让你想知道"这些单身人士真的是正确的方式吗?" 作为一名程序员,你必须相信自己的想法.你必须相信你会做出明智的决定.而这样做的唯一方法就是从制造错误决策时学习.因为我们都经常这样做.我们所能做的最好的事情就是确保我们不会反复做出同样糟糕的决定.
关于经理人课程,他们的问题是每个班级应该只有一个责任."经理班"的责任是什么?它....呃....管理的东西.如果你不能定义一个简洁的责任区,那么这个类是错误的.什么需要管理这些对象?管理它们意味着什么?标准库已经提供了用于存储一组对象的容器类.
然后你需要一些代码来负责绘制那里存储的所有对象.但这不一定是存储对象的对象.
还需要管理什么?找出"管理"这些对象的含义,然后了解管理所需的类.它很可能不是一个单一的任务,而是几种不同的责任,应该分成不同的类.
关于单身人士,我不会重复我之前多次说过的话,所以这里有一个链接.
最后一条建议:
拧紧OOP.真.好的代码不是OOP的代名词.有时课程是一个很好的工具.有时,它们只会混乱一切,并将最简单的代码片段隐藏在无穷无尽的抽象层之后.
看看其他范例.如果您使用的是C++,则需要了解泛型编程.STL和Boost是如何利用通用编程编写代码来解决许多问题的好例子,这些问题比等效的OOP代码更清晰,更好,更高效.
无论语言如何,从函数式编程中都可以学到许多宝贵的经验教训.
有时,简单的旧程序编程只是您需要的简单工具.
"良好设计"的关键不是尝试"良好的OO设计".如果你这样做,你就会把自己锁定在那个范例中.你不妨尝试找一个用锤子建造房子的好方法.我不是说这不可能,但如果你也允许自己使用其他工具,那么有更好的方法可以建造更好的房屋.
至于你的编辑:
对于第一个,DI会得到正确的答案吗?我是否应该给视图访问模型(这可能更像是一个MVC响应)?该视图是否会受益于实现接口(以便可以插入多个不同的视图)?
DI将是避免单身人士的一种选择.但是不要忘记老式的低技术选项:只需手动传递对需要了解"前"单例的对象的引用.
您的渲染器需要知道游戏对象列表.(或者它真的吗?也许它只有一个方法需要给出对象列表.也许渲染器类本身并不需要它)因此渲染器的构造函数应该被赋予对该列表的引用.这就是它的全部内容.当X需要访问Y时,在函数参数的构造函数中向它传递对Y的引用.与DI相比,这种方法的好处在于您可以非常明确地使用依赖项.您知道渲染器知道可渲染对象的列表,因为您可以看到传递给构造函数的引用.你必须写这种依赖性,让你有机会停下来问"这是必要的"吗?而且你有消除依赖关系的动机:这意味着更少打字!
您在使用单例或DI时最终会遇到的许多依赖关系都是不必要的.这两个工具都可以很容易地在不同模块之间传播依赖关系,这就是你所做的.然后你得到一个设计,你的渲染器知道键盘输入,输入处理程序必须知道如何保存游戏.
DI的另一个可能的缺点是一个简单的技术问题.并非所有语言都有可用的良好DI库.有些语言几乎不可能编写一个健壮的通用DI库.
在第二种情况下,如何构建应用程序?抱怨只是使用经理类而不是更具体的名称?或者是,在某些情况下,类可以进一步细分(例如ObjectHolder,ObjectDrawer,ObjectUpdater)?
我认为简单地重命名它们是一个好的开始,是的.就像我上面说的那样,"管理"你的对象是什么意思?如果我管理这些对象,我期望做什么?你提到的三个班级听起来像是一个很好的分工.当然,当你深入研究设计这些课程时,你可能想知道为什么你甚至需要一个ObjectHolder.这不正是标准库容器/集合类的作用吗?你需要一个专门用于"持有物体"的课程,还是只需使用一个List<GameObject>?
所以我认为你的选择真的都归结为同样的事情.如果您可以为类提供更具体的名称,那么您可能不需要将其拆分为多个较小的类.但是,如果您不能想到一个单一的名称来清楚该类应该做什么,那么它可能需要分解为多个类.
想象一下,你把你的代码放了半年.当你回来吧,你会有任何想法是什么"的ObjectManager"类的目的是?可能不是,但你会非常清楚"ObjectRenderer"的用途.它呈现对象.
| 归档时间: |
|
| 查看次数: |
2918 次 |
| 最近记录: |