处理多个对象时良好的编程风格

发布于 2024-08-30 17:51:24 字数 281 浏览 15 评论 0原文

我一直在编写棋盘游戏的软件版本。到目前为止,我已经编写了与游戏板上的物理对象相对应的类。我很擅长编写程序逻辑,但是我发现许多逻辑类需要访问相同的对象。

起初,我在调用方法时将适当的对象传递给方法,但这变得非常乏味,特别是当方法需要许多对象来执行其任务时。为了解决这个问题,我创建了一个类来初始化并存储我需要的所有对象。例如,这允许我通过调用 Assets.dice() 从任何类访问对象。

但现在想一想,这似乎不太对劲。这就是我来这里的原因,我担心我已经创造了某种神级。这种恐惧是毫无根据的,还是我创造了灾难的根源?

I've been programming a software version of a board game. Thus far I have written the classes which will correspond to physical objects on the game board. I'm well into writing the program logic, however I've found that many of the logic classes require access to the same objects.

At first I was passing the appropriate objects to methods as they were called, but this was getting very tedious, particularly when the methods required many objects to perform their tasks. To solve this, I created a class which initialises and stores all the objects I need. This allows me to access an object from any class by calling Assets.dice(), for example.

But now that I've thought about it, this doesn't seem right. This is why I'm here, I fear that I've created some sort of god class. Is this fear unfounded, or have I created a recipe for disaster?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

岁月无声 2024-09-06 17:51:25

您基本上已经遇到了单例模式。在大多数情况下,这是一个糟糕的模式。如果允许应用程序的任何部分几乎随时访问这样的全局数据,您最终会得到一团乱七八糟的代码,这些代码难以维护、调试,最重要的是难以测试。

我认为最好创建一个“上下文”,其中包含当前的骰子、棋子等,并根据需要将上下文传递给需要使用它的方法/类。这更干净,尽管是的,到处都要经过它很痛苦。但是您获得的优势是您可以跟踪谁在何时访问上下文,并且您还可以创建模拟上下文以用于测试目的。如果将上下文传递到高级对象中,并且它必须将其传递到其子组件,那么您从头到尾都知道上下文是什么以及它来自哪里。

另外,理想情况下,使 Context 不可变也是很好的。那可能是不可能的。但是,如果对于每个给定回合,您都可以创建一个捕获当前状态且不可变的新上下文,那么您的应用程序就会减少更多惊喜。

You've basically bumped into the singleton pattern. For the most part, it's a bad pattern. By allowing any part of your app to access essentially global data like this at just about any time, you end up with a spaghetti mess of code that's hard to maintain, debug, and most of all, test.

I think it is better to create a "Context", that contains the current dice, pieces, etc etc, and pass the context around as needed to methods/classes that need to use it. This is much cleaner, although yes it is a pain to have to pass it everywhere. But you gain the advantage that you can keep track of who is accessing the Context when, and also you can create mock Contexts for testing purposes. If you pass the context into a high level object, and it must pass it down to its sub components, you know from start to finish what the context is and where it came from.

Also, ideally, it's nice to make the Context immutable. That may not be possible. But if for each given turn if you can create a new Context that captures the current state and is immutable, you reduce even more surprise from your app.

心在旅行 2024-09-06 17:51:25

听起来您在询问面向对象编程的一般哲学。一般来说,您会发现将现实世界的对象建模为类并不总是对您的代码最有意义。

帮助我解决这个问题的一个指南是两个拟人类之间的对话(如果有人知道这句话的原始来源,我会很感激一个链接!):

A 类对 B 类说:“给我 x 的值。”

B类:“你为什么想要x的值?”

A 类:“这样我就可以用法兰连接它。”

B 类:“问我,我帮你修。”

这有助于让我们明白类的目的是封装数据并对其执行操作。总的来说,这个比喻可以帮助我更好地组织我的代码。

您可能想要查看的另一件事是一些常见的面向对象设计模式。像游戏骰子这样的东西可能作为 Singleton 更有意义,因为你不需要超过其中一个例子。

如果您想对设计模式有一个很好的介绍,我建议您选择优秀的 《Head First 设计模式》一书。

It sounds like you're asking about a general philosophy of Object-Oriented Programming. In general, you'll find that modelling real-world objects to classes doesn't always make the best sense for your code.

One guideline that's helped me figure this stuff out is a dialogue between two anthropomorphic classes (if someone knows the original source of this quote, I'd appreciate a link!):

Class A says to Class B: "Give me the value of x."

Class B: "Why do you want the value of x?"

Class A: "So I can flange it."

Class B: "Ask me, and I'll flange it for you."

This helps drive home the point that a class is meant to encapsulate the data and perform manipulations on it. In general, this is a parable that's helped me organize my code better.

Another thing you may want to look at are some common Object-Oriented Design Patterns. Something like game dice might make more sense as a Singleton, since you don't need more than one instance of it.

If you'd like a good introduction to Design Patterns, I'd recommend picking up the excellent Head First Design Patterns book.

浮华 2024-09-06 17:51:25

它真的是一个“上帝”类,还是仅仅是一个“上下文”,它是一个游戏的所有相互关联的对象实例的“容器”,然后将其传递给不同的方法调用(以便您只有一个参数)?后者非常常见,我认为它没有任何问题,但在这种情况下,容器本身没有真正的功能。

Is it really a "god" class, or merely a "context" which is a "container" for all those interrelated object instances of one game which is then passed alont to the different method calls (so that you have just one argument)? The latter is pretty common and I see nothing wrong with it, but in this case the container itself has no real functionality.

下雨或天晴 2024-09-06 17:51:25

感谢您提出这个问题。一段时间以来我一直在想同样的问题。跨方法传递对象并限制参数需要创建可以容纳所有这些对象的类。

不过,我认为设计还不错,因为您确实需要一个跨多个层的 Domain 类。如果这个 Domain 类没有携带必要的对象并且不执行任何逻辑,那么应该没问题。

Thanks for bringing this question. I have been wondering about the same issue for sometime now. Passing objects across method and keep parameters limited need creation of classes which can hold all these objects.

Still I think the design is not bad as you do need a Domain class which passes across multiple layers. If this Domain class is not carry necessary objects and not performing any logic it should be fine.

多情癖 2024-09-06 17:51:25

拥有那种可以访问所有内容的上下文类与拥有全局变量非常相似。同样的缺点也适用。全局变量可以通过任何方法读取和更改。这将使用全局变量的所有内容相互耦合。耦合是不好的,因为当事物耦合时,一个对象的变化可能会导致另一个对象发生变化。当耦合程度增加时,管理复杂性就变得非常困难(在我们的玩家类中,一只蝴蝶拍打翅膀可能会导致你的骰子类出现异常)。改变和额外的发展变得更加困难。难以检测和隐蔽的错误变得不可避免。

因此,例如,有一天在测试您的应用程序时,您可能会注意到您的骰子对象表现得很奇怪。你调用 dice.roll() 并看到它有时返回 1。但在这种情况下这是不可能的,因为你的玩家正在滚动其中两个。您进行调试并不知何故注意到 numberOfDice 属性在某个时刻更改为 1。使用像您这样的上下文方法,很难找到谁将 numberOfDice 更改为 1,因为每个人都可以通过您的上下文对象访问骰子。你明白了吗?

那么解决办法是什么呢?我喜欢的面向对象编程的比喻之一是分而治之。你需要找到可以相互隔离的行为、流程、对象。您需要将问题划分为可管理的部分,这些部分可以与应用程序中发生的其他内容隔离。

学习如何做到这一点当然并不容易,需要大量的学习、阅读、思考、讨论,当然还有编码。

Having that sort of a context class which has access to everything is very similar to having global variables. Same drawbacks apply. A global variable can be read and changed by any method. This couples everything that uses the global variable to each other. Coupling is bad because when things are coupled, a change in one object can cause something in the other object. When the degree of coupling increases it becomes very hard to manage the complexity (a butterfly flapping it's wings in our player class can cause an exception in your dice class). Change and additional development becomes harder. Hard to detect and obscure bugs become unavoidable.

So, for example, one day while testing you application you might notice that your dice object is acting weird. You call dice.roll() and see the it returns 1 sometimes. But that is not possible in this instance because your player is rolling two of them. You debug and somehow notice that the numberOfDice property got changed to 1 at some point. With a context method like yours it is not going to be easy to find who changed the numberOfDice to 1 because everybody has access to dice through your context object. You get the point?

So what is the solution? One of the metaphors that I like for OO programming is divide and conquer. You need to find behaviors, processes, objects that can be isolated from each other. You need to divide your problem into manageable pieces that can be isolated from the rest of the stuff going on in your application.

Learning how to do this is of course not easy and requires a lot of studying, reading, thinking, discussing and of course coding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文