使用Java的instanceOf与“接口编程”兼容设计原理?

发布于 2024-10-17 10:07:03 字数 708 浏览 6 评论 0原文

如您所知,“接口编程”设计原则总体上更喜欢超类型而不是具体类型或实现。

在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 技术交流群。

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

发布评论

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

评论(7

情独悲 2024-10-24 10:07:03

根据经验,您提到的“接口编程”原则可以翻译为:导入接口类型,没有任何编译时依赖项在子类上。

因此,你的问题的答案肯定是否定的。由于您转换为具体类型,因此您没有对接口进行编程。

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.

梦在深巷 2024-10-24 10:07:03

你自己也说过:

我的应用程序收到一个仓库。然而,Storehouse 并不是一个有用的操作类型。因为唯一真正有用的方法包含在具体类型中

。换句话说,您的 Storehouse 抽象不会给您带来任何东西……您为什么要拥有它?

您能否在 Storehouse 中创建抽象方法,并在每个具体类中实现,然后让您在客户端代码中以相同的方式处理具体类型?这就是抽象的目标。

You've said it yourself:

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

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.

木森分化 2024-10-24 10:07:03

并不真地。如果您的方法根据其接收的类型而具有截然不同的行为,那么多态性不会为您带来任何好处。您应该考虑两种单独的重载方法,一种采用 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 a ConcreteStorehouseB.

软甜啾 2024-10-24 10:07:03

这并不总是一种罪过。假设您正在实现一个规范,其中规定,如果 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.

俏︾媚 2024-10-24 10:07:03

如果不了解您正在执行的操作,可能很难确定,但更优雅的设计是让 StoreHouse 为不同的“操作”定义方法签名。然后,您只需执行操作,而不是 if(instanceof) 检查,具体仓库将实现这些操作。

public abstract class Storehouse
//add these definitions;
public void operation1();
public void operation2();

public class ConcreteStorehouseA

public void operation1() {
   //do operation
}

public void operation2() {
   //do operation
}

public class ConcreteStorehouseB

public void operation1() {
   //do operation
}

public void operation2() {
   //do operation
}

在您的调用代码中,而不是:

if (storehouse instanceof ConcreteStorehouseA) {
    ConcreteStorehouseA concreteStorehouseA = (ConcreteStorehouseA) storehouse;
    // perform operations
} else if (storehouse instanceof ConcreteStorehouseB) {
    ConcreteStorehouseB concreteStorehouseB = (ConcreteStorehouseB) storehouse;
    // perform operations
}

然后您可以使用多态性来执行操作,而无需关心正在执行哪个实现。

storehouse.operation1();
storehouse.operation2();

其中,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.

public abstract class Storehouse
//add these definitions;
public void operation1();
public void operation2();

public class ConcreteStorehouseA

public void operation1() {
   //do operation
}

public void operation2() {
   //do operation
}

public class ConcreteStorehouseB

public void operation1() {
   //do operation
}

public void operation2() {
   //do operation
}

In your calling code, instead of:

if (storehouse instanceof ConcreteStorehouseA) {
    ConcreteStorehouseA concreteStorehouseA = (ConcreteStorehouseA) storehouse;
    // perform operations
} else if (storehouse instanceof ConcreteStorehouseB) {
    ConcreteStorehouseB concreteStorehouseB = (ConcreteStorehouseB) storehouse;
    // perform operations
}

You can then use polymorphism to do the operations without caring which implementation is being executed.

storehouse.operation1();
storehouse.operation2();

where concreteStorehouseA and ConcreteStorehouseB have defined implementations for those operations.

楠木可依 2024-10-24 10:07:03

在这种情况下,听起来 Storehouse 抽象实际上根本不是一个正确的抽象。作为一种类型本身,它并没有真正为您提供任何东西。

可能有帮助的一件事是尽量不要将您的实现视为“类型”。 “类型”是类正在实现的抽象。 (基本上,在您的思考中将术语“类”和“类型”分开。)因此您正在使用的类型是 StorehouseConcreteStorehouseA 是一个 StorehouseConcreteStorehouseB 也是一个。那么问题就变成了,什么是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 a Storehouse, and so is ConcreteStorehouseB. So the question becomes, what is a Storehouse? 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

挽清梦 2024-10-24 10:07:03

正如很多人指出的那样,这不是针对接口进行编程。显然,接口抽象对于您的要求来说太弱了。

有多种方法可以解决这个问题,其中:

  • 如果界面在您的控制之下,您可以扩展它。考虑一下这是否值得,付出的代价可能太高了,特别是如果下一个要点成立的话。
  • 如果你最终只使用一种混凝土仓库,你可以直接使用它。
  • 如果您需要支持各种类型的仓库,一个不错的选择是定义您自己的接口,该接口准确提供您需要的抽象,并为每种具体类(适配器模式)编写一个薄包装器。

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:

  • If the interface is under your control, you can expand it. Consider whether that's worth it, it may be too high a price to pay, especially if the next bullet point holds.
  • If you end up using only one kind of concrete warehouse, you can just use that directly.
  • If you need to support various kinds of warehouses, a good alternative is to define your own interface that provides exactly the abstraction you need it and write a thin wrapper for each kind of concrete class (adapter pattern).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文