我正在讨论正确的面向对象设计,以使用 java 类中另一个对象的功能(方法),同时两个对象尽可能保持解耦。
例如,在我的类中的某个时刻,为了实现我的逻辑,我需要调用属于另一个对象(例如辅助类)的方法。这个帮助器类不需要以任何方式与我的原始类相关,它只是有一个特定的方法,该方法对我的类可见并且可供我的类使用。
实现逻辑后,就不再需要辅助方法(或辅助对象)。
显然,我需要引用这个辅助对象才能使用它的方法。但是为了强制封装,我不应该在原始类中声明一个实例变量来引用这个辅助对象吗?这个推理正确吗?此外,帮助程序类不知道任何可能使用它的客户端类。
在这种情况下,局部变量会更合适吗?在将使用其功能的方法中声明并实例化辅助对象?我的原始类中声明和实例化此类辅助对象的最佳位置在哪里?
我想知道是否有一个高级示例,或者是否在 OO 文章中对此进行了更详细的解释。我很感激任何以封装为中心的输入或上述提示。
I am debating the proper, OO-design to use another object's functionality (methods) from a java class, while both objects remain decoupled as much as possible.
For example, at some point in my class, to implement my logic, I need to call a method that belongs to another object, say a helper class. This helper class does not need to be in any way related to my original class, it just has a specific method which is visible to, and available for my class to use.
After the logic is implemented, the helper method (or the helper object) is not needed down the line.
Obviously, I would need a reference to this helper object in order to use its method. But to enforce encapsulation, I should not declare an instance variable in my original class to reference this helper object? Is that reasoning correct? Also, the helper class is not aware of any client class that might use it.
Would a local variable be more appropriate in this case? Declare and instantiate the helper object in the method which will make use of its functionality? Where is the best location in my original class to declare and instantiate such a helper object?
I was wondering if there is a high-level example, or if this is explained with a bit more elaboration in OO articles. I'd appreciate any encapsulation-focused input or hint on the above.
发布评论
评论(6)
不,声明实例变量与破坏封装无关。
相关注意事项是:
基本选择是:
更多你的功能 - 它是
在需要时创建,消失
一旦函数退出。可能是默认选择,其他一切都是优化或特殊情况。
构造函数 - 仅创建一次,但是
持续到你的对象本身得到
垃圾被收集/销毁。
使用 - 如上所述,但延迟
以复杂性为代价的创造。
高级选择:
保证一个将可用
你。对于某些事情来说工作正常,但是
很可能过度使用。
通过配置文件)打破了你的
封装并放入对象中
你会需要的。
执行此操作的所有其他方法(例如,将对象添加到构造函数或方法参数)都会向系统添加额外的依赖项,因此除非至少上述基本选择不合适,否则不应执行此操作。
No, declaring an instance variable has nothing to do with breaking encapsulation.
The relevant considerations are:
The basic choices are:
more of your functions - it is
created when needed, goes away as
soon as the function exits. Probably the default choice, everything else is an optimisation or special case.
constructor - created only once, but
last until your object itself gets
garbage collected/destroyed.
used - as above, but delaying
creation at the cost of complexity.
Advanced choices:
guaranteeing one will be available to
you. Works ok for some things, but
very possible to overuse.
by configuration files) breaks your
encapsulation and puts in the object
you will need.
All the other ways of doing this (e.g. add the object to constructor or method arguments) add extra dependencies to the system and so shouldn't be done unless at least the basic choices above aren't suitable.
正确的答案取决于辅助类 (H) 和您在其上使用的方法 (M) 与原始对象类 (C) 之间关系的性质。您提到了几个关键点:
C
中。H
中。HM()
仅由C
使用一次。H
与客户端无关。H
和M()< /code> 是一个实例方法。
有几个解决方案:
评估
M
作为静态方法是否会更好。如果我',这对于静态方法来说是一个非常引人注目的用途。我见过一个。您没有提到任何有关 H 维护状态的内容。使用策略模式。如果
HM()
表示执行某事的特定方式,则H
是该模式中的策略对象对于C
。如果还有其他类似H
的类具有类似的M()
方法,那么您可以从中选择不同的策略。The right answer depends on the nature of the relationship between the helper class (H) and the method you use on it (M), and the original object class (C). You mentioned a few key points:
C
.H
instead.H.M()
is used only once byC
.H
is client-agnostic.H
and thatM()
is an instance method.There are a couple of solutions:
Assess whether
M
wouldn't be better as a static method. This is a very compelling use for a static method if I've ever seen one. You don't mention anything about H maintaining state.Use the Strategy pattern. If
H.M()
represents a specific way of doing something, thenH
is the Strategy object in the pattern forC
. If there are otherH
-like classes with similarM()
methods, these are the different strategies you can pick from.那么是这样的场景吗?这些是问题吗?
Q1.我认为你应该将 aHelper 声明为接口
然后我们不耦合到任何特定的实现。
Q2。如果您只在一个地方使用它,则在该函数中声明它,否则作为成员变量。这样做不会增加耦合。
Q3。在构造函数中或使用工厂的惰性 getter 进行初始化。
这可以使测试变得非常容易,您的测试可以注入一个模拟助手类。
或者您可以使用惰性初始化器。如果您的助手是方法中的局部变量,那么这非常方便。同样,工厂可以根据您的喜好注入或静态。
So is this the scenario? Are these the questions?
Q1. I think you should declare aHelper as an Interface
Then we are not coupled to any specific implementation.
Q2. If you only use it in one place declare it in that function, otherwise as a member variable. You don't increase coupling by doing either.
Q3. Initialise either in a constructor or with a lazy getter using a factory.
This can make testing very easy, your tests can inject a Mocked Helper class.
Or you can use a lazy intialiser. This is quite handy if your helper is a local variable in your method(s). Again the factory can be injected or be static depending upon your preference.
静态方法很难测试,或者更确切地说,在另一个方法中调用的静态方法很难模拟。我发现通过测试来思考很容易做出好的设计。如果该方法是非静态成员,您可以轻松地对调用该方法的代码进行单元测试,而无需测试该方法。你和我在一起吗?假设方法 m 使用网络来做事。如果该方法是静态的,则每次测试使用方法 m 的代码时,它都会在网络上执行操作。如果网络失败,你的测试就会失败,但你想要测试的代码不会失败。你看?如果它不是静态的,您可以使用该方法模拟该对象,并使其始终返回“OK”。
也就是说,我会将助手作为参数发送给方法,或者更确切地说是助手接口。这样你的类就完全不知道如何创建助手,甚至不知道是什么类型。无知是福。班级只会知道如何使用它,美丽的东西。 :)
Static methods are hard to test, or rather static methods beeing called in another method is hard to mock. I find it easy to do good design by thinking in terms of testing. If the method is a non-static member, you can easily unit-test code calling that method without also testing that method. Are you with me? Let's say a method m uses the network to do stuff. If that method is static, every time you test code that uses the method m, it will do stuff at the network. And if the network stuff fails, your test fails, but not the code you want to test. You see? If it is not static, you can mock the object with the method, and make it always return "OK".
That beeing said, I would send the helper as a parameter to the method, or rather a helper-interface. That way your class is totally oblivious of how to create a helper, or even what type. Ignorance is bliss. The class will only know how to use it, beautiful stuff. :)
你在这方面投入了太多的精力。解耦并不意味着完全没有联系。如果您打算使用辅助对象一次,只需将其作为参数传递给使用它的块的代码,或者让您的类从工厂获取它的实例。
但在某些时候你必须对它有一个参考。显然您不希望有一个成员实例引用它(潜在的内存泄漏)。因此,这将调用某种工厂或实例管理器来为您提供对助手的引用。
但不要太过分了。我们的目标是找到一个解决方案,而不是玩解耦游戏,让事物适应人为的、冗余的类层次结构。后者是 OO 概念最糟糕的用法。
You are putting too much effort in this. Decoupling does not mean not having a connection at all. If you are going to use the helper object once, just pass it as a parameter to the code of block that uses it, or have your class get an instance of it from a factory.
But at some point you have to have a reference to it. Obviously you do not want to have an member instance referencing it (potential memory leak). So that would call some sort of factory or instance manager that gets you a reference to a helper.
But don't go overboard with this. The goal is to get a solution, not to play decoupling games and getting things fit into artificial, redundant class hierarchies. The later is the worst usage of OO concepts.
为什么不选择静态方法,或者使用单例辅助对象?
Why don't you go for a static method, or have a singleton helper object?