使用Java的instanceOf与“接口编程”兼容设计原理?
如您所知,“接口编程”设计原则总体上更喜欢超类型而不是具体类型或实现。
在Java程序中使用instanceof从超类型派生具体类型符合原理吗?
在我的应用程序中,Storehouse 是一个抽象超类型类,具有几个私有变量以及公共 getter 和 setter。
ConcreteStorehouseA继承自Storehouse,有很多具体的方法和变量。 ConcreteStorehouseB 类似但又不同。
我的应用程序收到一个仓库。然而,Storehouse 并不是一个有用的操作类型。因为唯一真正有用的方法包含在具体类型中,所以我按如下方式使用instanceof:
if (storehouse instanceof ConcreteStorehouseA) {
ConcreteStorehouseA concreteStorehouseA = (ConcreteStorehouseA) storehouse;
// perform operations on the concrete type's useful methods and variables
使用instanceof是否符合原则?
编辑:
本质上,该应用程序是桌面角色扮演游戏《Shadowrun》的骰子模拟器。具体类型是不同的测试类型——成功测试、反对测试、扩展测试——它们的成功运行都有非常不同的因素和参数。超类型本质上包含骰子池!
As you know the 'program to an interface' design principle broadly prefers supertypes instead of concrete types or implementations.
Is it consistent with the principle to use instanceof in a Java program to derive a concrete type from a supertype?
In my application, Storehouse is an abstract supertype class with a couple of private variables and public getters and setters.
ConcreteStorehouseA inherits from Storehouse and has a lot of concrete methods and variables. ConcreteStorehouseB is similar but different.
My application receives a Storehouse. However, Storehouse is not a useful type to operate on. Because the only really useful methods are contained in the concrete types, I use instanceof as follows:
if (storehouse instanceof ConcreteStorehouseA) {
ConcreteStorehouseA concreteStorehouseA = (ConcreteStorehouseA) storehouse;
// perform operations on the concrete type's useful methods and variables
Is using instanceof compatible with the principle?
Edit:
In essence the application is a dice simulator for a table top RPG, Shadowrun. The concrete types are the different test types - Success Test, Opposed Test, Extended Test - which all have very different factors and parameters for their successful operation. The supertype essentially contains the dice pool!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
根据经验,您提到的“接口编程”原则可以翻译为:
导入
仅接口类型,没有任何编译时依赖项在子类上。因此,你的问题的答案肯定是否定的。由于您转换为具体类型,因此您没有对接口进行编程。
As a rule of thumb, that "program to interfaces" principle that you mentioned can be translated into:
import
only the interface type, don't have any compile-time dependency on subclasses.Therefore, the answer to your question would be definitely no. You are not programming to interfaces since you cast to concrete types.
你自己也说过:
。换句话说,您的
Storehouse
抽象不会给您带来任何东西……您为什么要拥有它?您能否在
Storehouse
中创建抽象方法,并在每个具体类中实现,然后让您在客户端代码中以相同的方式处理具体类型?这就是抽象的目标。You've said it yourself:
In other words, your
Storehouse
abstraction isn't buying you anything... why do you have it?Could you create abstract methods in
Storehouse
, implemented in each concrete class, which would then let you treat the concrete types the same way in your client code? That's the goal of the abstraction.并不真地。如果您的方法根据其接收的类型而具有截然不同的行为,那么多态性不会为您带来任何好处。您应该考虑两种单独的重载方法,一种采用
ConcreteStorehouseA
作为参数,另一种采用ConcreteStorehouseB
作为参数。Not really. If your method has wildly different behaviour depending on the type that it receives, then polymorphism is buying you nothing. You should consider two separate overloaded methods, one taking a
ConcreteStorehouseA
as an argument, and the other taking aConcreteStorehouseB
.这并不总是一种罪过。假设您正在实现一个规范,其中规定,如果 x 是 A 则执行此操作,否则如果 x 是 Y 则执行此操作。最好让您的代码看起来像规范。人为地将其切成小块并将它们放入不同的源中,不仅自命不凡,而且复杂、不安全、难以理解和难以维护。
编程关注点是多维的。编程语言是一维的,至少目前是这样。如何紧密地组织相关的关注点是一门艺术。不要相信关注点必须根据类分解的教条,那么一个关注点最多只能引用一个类,并且它必须驻留在该类中。
根据那些知道如何编写更好软件的专家的说法,上个世纪软件工程中有一个大禁忌:那就是不惜一切代价避免代码更改。如果您要更改之前编写的某些源代码,宇宙随时可能崩溃成一颗花生。因此,您最好从一开始就设计一个完美的架构,然后可以通过添加新的/干净的类来完成需求的任何更改,而无需触及现有的代码库。
也就是说,让我在这里用非常精确的措辞,完全是胡说八道,即使在当时也是如此。
如今,我们拥有更好的工具,并且代码更改不仅安全,甚至受到鼓励。确保明天由于不可预见的原因而轻松更改代码的最佳方法是让今天的代码尽可能简单。以即使是逗号也能理解的方式编写代码。
It is not always a sin. Suppose you are implementing a spec, which says, if x is A do this, else if x is Y do that. It's better to have your code look like the spec. To artificially cut it into little pieces and places them into difference sources, is not only pretentious, but also complicated, unsafe, hard to understand and hard to maintain.
Programming concerns are multi-dimensional. Programming languages are one dimensional, at least for now. It is an art how to organize related concerns closely. Do not buy into the dogma that concerns must be decomposed according to classes, then a concern can at most reference one class, and it must reside inside that class.
Last century there was this great taboo in software engineering, according to the experts who knew how to write better softwares: that is, code change should be avoided at all cost. If you are going to change some source code you wrote previously, the universe could collapse into a peanut at any moment. So you better design a perfect architecture from the start, and then any change in requirement can be done by adding a new/clean class, without touching existing code base.
That was, let me be very precise in wording here, total nonsense, even back then.
Today, we have much better tools, and code change is not only safe, it's even encouraged. The best way to make sure code change is easy tomorrow due to unforeseeable reasons, is to keep code today as simple as possible. Write code in a way that you can understand even in a comma.
如果不了解您正在执行的操作,可能很难确定,但更优雅的设计是让 StoreHouse 为不同的“操作”定义方法签名。然后,您只需执行操作,而不是 if(instanceof) 检查,具体仓库将实现这些操作。
在您的调用代码中,而不是:
然后您可以使用多态性来执行操作,而无需关心正在执行哪个实现。
其中,concreteStorehouseA 和 ConcreteStorehouseB 已定义这些操作的实现。
It can be difficult to be sure without insight into what operations you are performing, but a more elegant design would be to have StoreHouse define method signatures for the different "operations". Then, instead of the if(instanceof) checks, you just execute the operations, and the concreteStorehouses would implement those operations.
In your calling code, instead of:
You can then use polymorphism to do the operations without caring which implementation is being executed.
where concreteStorehouseA and ConcreteStorehouseB have defined implementations for those operations.
在这种情况下,听起来
Storehouse
抽象实际上根本不是一个正确的抽象。作为一种类型本身,它并没有真正为您提供任何东西。可能有帮助的一件事是尽量不要将您的实现视为“类型”。 “类型”是类正在实现的抽象。 (基本上,在您的思考中将术语“类”和“类型”分开。)因此您正在使用的类型是
Storehouse
。ConcreteStorehouseA
是一个Storehouse
,ConcreteStorehouseB
也是一个。那么问题就变成了,什么是Storehouse
?这就是定义每个类型的类型。在这种特殊情况下,听起来不同的
Storehouse
实现是如此不同(至少在它们当前的实现中),以至于它们并没有真正共享有价值的抽象。这种情况下的抽象“类型”只是通过继承的方式提供一些通用功能,而不是实际抽象类型。换句话说,听起来这里的
Storehouse
实现是 Liskov Substitution 励志海报的经典示例:http:// /www.lostechies.com/blogs/derickbailey/archive/2009/02/11/solid-development-principles-in-motivational-pictures.aspx
It sounds like the
Storehouse
abstraction isn't really a proper abstraction at all in this case. As a type by itself it isn't really providing you with anything.One thing that may help is to try not to think of your implementations as "types" at all. The "type" is the abstraction that the class is implementing. (Basically, pull apart the terms "class" and "type" in your thinking.) So the type you're working with is a
Storehouse
.ConcreteStorehouseA
is aStorehouse
, and so isConcreteStorehouseB
. So the question becomes, what is aStorehouse
? That's the type that defines what each one is.In this particular case it sounds like the different
Storehouse
implementations are so different (at least in their current implementation) that they don't really share a worth-while abstraction. The abstract "type" in this case is just providing some common functionality by means of inheritance rather than actually abstracting the type.To put it another way, it sounds like the
Storehouse
implementations here are a classic example of the Liskov Substitution motivational poster here:http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/solid-development-principles-in-motivational-pictures.aspx
正如很多人指出的那样,这不是针对接口进行编程。显然,接口抽象对于您的要求来说太弱了。
有多种方法可以解决这个问题,其中:
As various people have pointed out, this is not programming to the interface. Apparently, the interface abstraction is too weak for your requirements.
There are various ways to deal with this, among which: