实现接口并具有公共属性的最佳实践(如果全部)是什么?
我实际上要问的是,如果我希望所有实现都具有公共(但不是静态!)属性,是否有比使用抽象类更好的方法。
例如:
public interface MyInterface{
public int someProperty = 0;
public void doSomething();
}
public ClassA implements MyInterface{
@Override
public void doSomething(){...}
}
public ClassB implements MyInterface{
@Override
public void doSomething(){...}
}
有没有办法创建这两个实现的实例并初始化接口的 someProperty 成员?
或者我必须使用抽象类而不是接口来为每个实现实例初始化这个成员?
回答
Java 中的接口没有成员字段,只有方法。(此处讨论。)换句话说,接口定义了行为,而不是状态。
你可以暗示的属性具有JavaBean风格的访问方法存在着get…与set…您的接口中声明。
如果您想确保每个对象都有自己的特定名称的特定类型的成员字段,那么是的,正如您所建议的那样,定义一个具有该字段的抽象类。
当然,您可以同时执行以下两种操作:编写一个抽象类,其中包含实现需要访问器方法的接口的成员字段。两者都做是否是一个好主意取决于您的具体情况。
下面是一种可能的示例场景,用于 (a) 一个带有成员字段的抽象类,以及 (b) 一个需要 getter/setter 访问器方法的接口。我不完全确定这个例子中我的逻辑的完整性,但希望它传达了总体思路。
车辆种类繁多。有些在公共街道上使用是合法的,有些则不是。上街合法的一方面是拥有车辆识别号 (VIN)。
让我们定义一个车辆的层次结构。
Vehicle是祖父超类,并且是抽象的。GoKart是 的一个子类Vehicle,也是抽象的,在街上开车是不合法的。Vin是代表我们的车辆识别号 (VIN) 类型的记录。Car是 的另一个子类Vehicle,也是抽象的。但是在街上开车是合法的。这个抽象类带有一个protectedtype的类成员Vin,由任何子类继承。- 为了将
Car类及其子类标记为合法,我们定义了一个StreetLegal接口。该接口定义了一对方法,以暗示Vin在实现此方法的所有类上都存在一个属性。 - 为了将所有这些结合在一起,我们有一个
HondaElement用于特定类型汽车的示例具体类。
package work.basil.example.cartalk;
public abstract class Vehicle
{
}
package work.basil.example.cartalk;
// Not street-legal.
// https://en.wikipedia.org/wiki/Go-kart
public abstract class GoKart extends Vehicle
{
public boolean hasRemoteSpeedControl ;
}
package work.basil.example.cartalk;
// VIN = Vehicle identification number.
// https://en.wikipedia.org/wiki/Vehicle_identification_number#North_American_check_digits
public record Vin(String countryCode, int checkDigit, String serialNumber)
{
// Add constructor to validate data.
}
package work.basil.example.cartalk;
public abstract class Car extends Vehicle implements StreetLegal
{
protected Vin vin ;
}
package work.basil.example.cartalk;
public interface StreetLegal
{
public Vin getVin ( );
public void setVin ( Vin vin );
}
package work.basil.example.cartalk;
public class HondaElement extends Car implements StreetLegal
{
public HondaElement ( Vin vin )
{
this.vin = vin; // Accessing member field defined on abstract superclass `Car`.
}
@Override
public Vin getVin ( )
{
return this.vin; // Accessing member field defined on abstract superclass `Car`.
}
@Override
public void setVin ( Vin vin )
{
this.vin = vin; // Accessing member field defined on abstract superclass `Car`.
}
}