【问题标题】:Interfaces, Classes and Code Smell接口、类和代码异味
【发布时间】:2017-05-06 12:59:06
【问题描述】:

假设我有以下interfaces

public interface GameObject {
    void viewDetails();
}

public interface Weapon extends GameObject {
    void attack();
}

//A weapon is not the only item reloadable. A container could be refilled. 
public interface Reloadable extends GameObject {

    void replenish (final int amount);
}

和实施:

public final class ReloadableWeapon implements  Reloadable, Weapon {


    private String weaponName;
    private int numberofbullets;

    public ReloadableWeapon(String name, int bullets){

        this.weaponName = name;
        this.numberofbullets = bullets;
    }


    @Override
    public void replenish(final int amount) {
        this.numberofbullets = amount; 
    }

    @Override
    public void attack() {
        System.out.println(this.weaponName + " fired");
        this.numberofbullets--;
        System.out.println("Shots Left: " + this.numberofbullets);
    }


    @Override
    public void viewDetails() {
        System.out.println(this.weaponName);

    }
}

在 Effective Java 中,其中一章建议我应该通过 interface 声明我的类。我了解优点,但如果我有多个interface 怎么办?

在我的主要方法中,我这样声明:

ReloadableWeapon chargeGun = new ReloadableWeapon("ChargeGun",10);

并像这样使用它:

public static void reloadGameWeapon(Reloadable reload){
        reload.replenish(10);
}

public static void attackGameWeapon(Weapon toAttackwith){
        toAttackwith.attack();
}

如果我通过interface声明它,我显然只会得到特定接口提供的方法。我可以创建另一个名为 ReloadedableWeapon 的interface,但是会在那里放置哪些方法?我是如何声明使用我的 ReloadableWeapon 不好的做法或代码味道?

【问题讨论】:

  • “在 Effective Java 中,其中一章建议我应该通过接口声明 [原文如此] 我的类。”通过接口声明一个类是没有意义的。你应该引用书中的确切段落。我们不知道您对这本书的理解是否正确。
  • Effective Java 建议你在接口代表或捕获类的目的时使用接口类型。您定义的接口不属于此类别。这些接口是混合的,即。指示类的补充行为的接口(如 Comparable)。
  • 这些接口不应相互继承。
  • @LewBloch - 为什么不呢?你会怎么做?
  • 有时您需要在一个接口中使用多种行为(方法),但大多数情况下,每个接口最好有一个抽象方法来体现其主要语义。该类提供了 mixin。 public class ChargeGun implements Replenishable, Weapon, GameItem {。 “接口编程”是指你根据当下的需要,为每个不同的接口声明一个变量。大多数情况下,您只需调用方法,chargeGun.replenish();,而不是通过包装 1 行方法调用来伤害模型。不需要变量。

标签: java class interface


【解决方案1】:

您可以创建一个同时扩展WeaponReloadable 的接口。

public interface WeaponReloadable extends Weapon,Reloadable {
   ...
}

并且有这个实现:

public final class MyWeaponReloadable implements  WeaponReloadable  {
   ...
}

通过这种方式,您可以创建一个使用ReloadableWeapon 接口声明的MyReloadableWeapon 实例,并将其传递给带有ReloadableWeapon 参数的方法:

WeaponReloadable weaponReloadable = new MyWeaponReloadable();
reloadGameWeapon(weaponReloadable);
attackGameWeapon(weaponReloadable);

【讨论】:

  • 我想过这个,但正如我所说,新的 ReloadableWeapon 界面会发生什么? Weapon 和 Reloadable 可以满足我的需求。
  • @Nexusfactor 该接口的主体可以为空。它的唯一目的是提供“交集类型”。
  • 创建一个空界面不是很糟糕吗?
  • 并非如此。对于没有“一流”类型的交叉点,这是一个非常有效的解决方法。还有像java.io.Serializablejava.util.RandomAccess 这样的“真正空”的标记接口。有时你需要这些东西。
  • 创建一个空接口来“相交”两个接口本身并不是一个好或坏的做法。这是一种适合您特定要求的特殊做法:通过接口s 使用必须符合两个不同接口的对象进行编程,而这两个接口之间没有任何关系。
【解决方案2】:

您可以使用泛型来获得类型交集:

 public static <W extends Weapon & Reloadable> doSomething(W weapon){
     weapon.replenish(10);
     weapon.attack();
 }

通常,只创建一个“交叉接口”会更容易

interface ReloadableWeapon extends Weapon, Reloadable {}

但泛型方法甚至适用于您无法修改类型层次结构以包含该新接口的类(即第三方代码)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 2017-04-07
    • 2010-10-12
    • 2018-03-21
    相关资源
    最近更新 更多