【问题标题】:Java - Is there such a thing as too many interfaces?Java - 接口太多了吗?
【发布时间】:2018-11-14 00:06:36
【问题描述】:

我已经编程了几年了。接口似乎一直是我难以理解的话题。将尽可能多的功能抽象到接口中是一种好习惯吗?

我从来没有完全理解它们的好处。我一直认为“为什么不正常编写方法”。它们只是方法。然后我开始学习依赖注入,以及它如何真正简化代码,让构造函数成为类与外界的主要联系点。

但是,最近,我再次开始思考接口,以及如何将它们像类型一样扔掉,而不仅仅是标记方法的可爱方式。

所以在我第一次在 Java 中使用接口的真实实验中,我做了这个例子,我想知道的是:

对于了解接口强大功能的 Java 开发人员,我写的这个小 sn-p 代码说明了一个好的模式还是好的思路?到目前为止,基本上这是好的代码吗?我只想知道我是否走在正确的道路上。我明天要进行第二次工作面试,并且希望在面试中提出这一认识,前提是我走在正确的道路上。

代码如下:

interface Fightable{
void kick(Fightable enemy);
void punch(Fightable enemy);
void takeDamage(Fightable enemy, String typeOfStrike);
void strikeEnemy(Fightable enemy, String typeOfStrike);
}

interface CanEat{
void chew();
void swallow();
}

interface MotherShip{
int motherShipBoost = 50;
String getColony();
void sendHelp(int[] location);
String buildMoreShips(int amount);
void flyToNewSystem(String newSystem);
int[] beamDownRandomly();
}

interface Animatable{
void animateChew(CanEat eater);
void animateSwallow(CanEat eater);
void animateMove(Moveable mover);
void animateRevive(CanEat eater);
void animateStrike(Fightable striker, Fightable receiver, String typeOfStrike);
}

interface Moveable{
void setNewLocation(int []newLocation);
int[] getLocation();
void move();
}

public class GameCharacter implements Fightable, CanEat, Moveable{

private int health;
private String name;
private int[] location;
private String stamina;
private String origin;
private String colony;
private Animatable animator;
private MotherShip motherShip;
private boolean isRecruited;

public GameCharacter(MotherShip motherShip, String name, Animatable animator){
    this.motherShip = motherShip;
    this.animator = animator;
    this.name = name;
    this.location=this.motherShip.beamDownRandomly();
    this.colony = this.motherShip.getColony();
}


@Override
public void kick(Fightable enemy) {
    strikeEnemy(enemy, "KICK");

}



@Override
public void punch(Fightable enemy) {
    strikeEnemy(enemy, "PUNCH");
}

@Override
public void takeDamage(Fightable enemy, String typeOfHit) {
    this.health = this.health - 3;
    animator.animateStrike(enemy, this, typeOfHit);
    if(this.health < 10){
        motherShip.sendHelp(this.location);
    }
}

@Override
public void strikeEnemy(Fightable enemy, String typeOfStrike) {
    enemy.takeDamage(this, typeOfStrike);
    animator.animateStrike(this, enemy, typeOfStrike);
}

@Override
public void chew() {
    animator.animateChew(this);

}

@Override
public void swallow() {
    animator.animateSwallow(this);
    health = health + 10;
    animator.animateRevive(this);
}

@Override
public void setNewLocation(int[] newLocation) {
    this.location = newLocation;
}

@Override
public int[] getLocation() {
    return this.location;
}

@Override
public void move() {
    animator.animateMove(this);
}
}

看起来我的想法是对的吗?

感谢您的反馈

-T

【问题讨论】:

标签: java class design-patterns dependency-injection object-oriented-analysis


【解决方案1】:

首先,接口的存在是为了实现其中描述的所有非默认方法。这可以很容易地被抽象类取代。但是,为了以更简单的方式进行清理,已经实现了接口。

只要界面看起来合乎逻辑且易于使用,就没有太多界面之类的东西。但是,一旦您或您的同事为获取图片而头疼,那就太过分了。

使用接口作为简化清理和结构化流程的一种额外方式。

此外,java 不支持类的多重继承。因此,通过使用接口,您可以像在示例中那样进行多重继承。

干得好,祝你面试顺利!

【讨论】:

  • 感谢您的优雅回复。这说得通。因此,只需使用您和您的团队在概念上可以管理的数量即可。不过,我确实觉得这种理解可以为程序员带来一些突破。这似乎是一种保持类之间关系随意的简单方法。测试似乎也会更容易。
  • 就是这样!此外,正如我添加的那样,java 在类的情况下不支持多重继承。因此,通过使用接口,您可以像在示例中那样进行多重继承。这是我的荣幸!
【解决方案2】:

我会尽力不可知地回答您的问题。

1.

将尽可能多的功能抽象到接口中是一种好习惯吗? 让我们从基础开始 a)记住接口只不过是“合同”,实现接口的参与者基本上承诺兑现和交付合同条款和条件的承诺。 b) 接口在代码中充当优秀的设计工具,本质上允许生产者和参与者专注于他们的高级交互,而不用担心实现细节。

在 CS 基础知识外行人的术语中,接口承诺一致性,本质上是 3 件事。 1. 对上述功能/操作/功能/方法可用的承诺 2. 该功能接受上述商定的输入 3.(如果实施)此功能将产生上述结果。

因此,当一项服务(类/soap 消息等)提供实现接口的意图时,它公开同意“合同”的这 3 个条款,任何偏离它们的行为都违反了合同。

2.

是的,你是绝对正确的,当涉及到SOLID design principles 中的 Ioc(控制反转)时,接口确实展示了它们的强大功能,它允许 IoC 容器解析(提供)并服务于合适的参与者(实现)合同,通常在运行时,因此使系统开发人员不必担心实施细节。

但也许 Ioc 的好处通常只有在实现 service locator pattern 时才能实现,因此,“开发人员或团队如何从使用接口作为设计工具中获益?”成为一个重要的问题。

单一开发者 举个例子,我正忙着写一个新的软件系统,白天,我全神贯注于我想为我的用户提供的那种功能,也许能够在一般意义上管理他们的待办事项列表,这需要能够“创建”新的待办事项、“清除检查”现有项目以及从待办事项集合中“删除”项目。现在有几种方法可以实现这些特性中的每一个,我变得懒惰了,我宁愿在下周只交付其中一个特性,但我可能会忘记我最初的想法并最终实现我自己的基于特性的特性随着时间的推移,我受到了影响,为了训练自己并坚持我最初的想法,我选择在不实际实施的情况下预先起草此功能的合同,这将使我能够模拟这些功能而不是实际实施它们。因此,通过使用接口,我已经为接下来几周需要实现的目标奠定了基础,并且我可以每隔一天回到它并完成我的功能而不会违背我的承诺......这将我们带到下一个主题我现在不会深入研究Open Close principles(SOLID 中的 O),它基本上说我的设计对外部更改是封闭的,但对内部更改是开放的,也许是对扩展(添加)开放的事件。所以我可以在不破坏现有合同的情况下向我的 todo 服务添加新功能,并且我可以更改它们的实现行为但不能更改现有功能的形状。

在一个团队中 我与 Lindile 和 Selebalo 合作实施虚拟卡系统,由于工作量太大,我们决定我将专注于核心银行系统(余额分类账),Lindile 将专注于 VC 的存款,而 Selebalo 专注于VC的存款。在我们的初始设计会议中,我们从核心银行开始从内到外进行设计,并描述哪些操作可用于更新客户的账户,经过几个小时的讨论,我们决定核心银行系统将提供两种功能,一种用于添加将钱存入一个帐户,称为“贷方”,接受金额;“借方”,扣除或减少也接受金额的客户帐户。但由于核心必须处理除借方和贷方之外的许多其他事情(客户信用档案、AML 等),因此我可能需要一段时间才能说这些人可以集成和测试他们的代码,所以我们决定签订一份

public interface ICoreBankingServices{

Balance Debit(decimal amount,Currency c);
Balance Credit(decimal amount, Currency c);

}

现在 Lindile 和 Selebalo 可以假设我将履行合同并选择模拟或模拟借方和贷方的结果,直到我们都准备好进行集成和测试,因此我的功能对他们没有开发依赖性工作,这是一件好事。

我希望这些示例描述了使用接口、设计工具和依赖解耦机制的一些基本好处。

我不是 Java 的期望,但如果游戏角色必须战斗、吃饭和移动,那么你就在正确的轨道上。您只需要注意您所做的解耦级别(与规范化相同),但会增加复杂性,但没有指导方针,只要事情不会变得太复杂,您可以用在逻辑上尽可能多的接口......在多重实现继承时不要应用相同的想法,但这是个人意见 :)

您最终将不得不缴纳税款并更多地了解设计模式以及它们试图解决或简化的问题,以便加深对设计更好系统的理解。

【讨论】:

    猜你喜欢
    • 2011-02-15
    • 1970-01-01
    • 2012-02-15
    • 1970-01-01
    • 2011-07-26
    • 1970-01-01
    • 1970-01-01
    • 2017-06-28
    • 2013-01-10
    相关资源
    最近更新 更多