问题
I want to make an interface that forces each class that implements it to have a certain functionality, for the implemented class' type.
So say I have classes MyClassA, MyClassB, MyClassC, etc. that all need a function on their own type:
in MyClassA:
public class MyClassA implements MyClass {
MyClassA function(MyClassA x) {
doSomethingImplementedInMyClassA(x);
}
}
in MyClassB:
public class MyClassB implements MyClass {
MyClassB function(MyClassB x) {
doSomethingImplementedInMyClassB(x);
}
}
The question is, how to write the interface MyClass to require such function?
public interface MyClass {
MyClass function(MyClass x);
}
obviously doesn't work, since the returning type is MyClass and not its implementation. How to do this properly in Java?
回答1:
You can use generics:
public interface MyClass<V extends MyClass<V>> {
V function(V x);
}
public class MyClassA implements MyClass<MyClassA>
This is called the CRTP.
This is not perfect; it would still allow things like
public class MyClassB implements MyClass<MyClassA>
To do this correctly, you need higher-kinded types [citation needed], which Java does not support.
回答2:
If the implementation always calls a method on the argument, why not just add that method to the interface?
interface MyClass {
MyClass doSomething();
}
class MyClassA implements MyClass {
MyClassA doSomething() {
//implementation here
}
}
class MyClassB implements MyClass {
MyClassB doSomething() {
//implementation here
}
}
回答3:
What you probably need is a parent class apart from an interface.
I find an interface is ideally used to define behavior thus GroupElementA is a GroupElement sounds conceptually more accurate rather than GroupElementA behaves like a GroupElement.
I would consider using a parent class to achieve what you want to have.
/**
* An abstract group element.
*/
abstract class GroupElement
{
// attributes of all group elements
}
/**
* Defines behavior for objects that can be multiplied with
* GroupElements.
*/
interface GroupElementMultipliable
{
public GroupElement multiplyBy(GroupElement groupElement);
}
/**
* Defines behavior for objects that can be divided by
* GroupElements.
*/
interface GroupElementDivisible
{
public GroupElement divideBy(GroupElement groupElement);
}
/**
* An abstract GroupElement that can perform operations like
* multiplication and division.
*
* Then again this class may not be necessary. The interfaces
* implemented here may actually be directly implemented by
* GroupElementA. GroupElementA will also be the one to inherit
* GroupElement.
*/
abstract class OperableGroupElement extends GroupElement
implements GroupElementMultipliable, GroupElementDivisible
{
// attributes of all operable group elements
}
/**
* A concrete GroupElement that can perform operations like
* multiplication and division.
*/
class GroupElementA extends OperableGroupElement
{
@Override
public GroupElementA multiplyBy(GroupElement groupElement)
{
// Since we expect to multiply with another GroupElementA
// we attempt to typcast the groupElement
GroupElementA groupElementA = (GroupElementA) groupElement;
// do multiplication operation -- this * groupElementA
// then return new self
return this;
}
@Override
public GroupElementA divideBy(GroupElement groupElement)
{
// Since we expect to divide by another GroupElementA
// we attempt to typcast the groupElement
GroupElementA groupElementA = (GroupElementA) groupElement;
// do division operation -- this / groupElementA
// then return new self
return this;
}
}
回答4:
The proper way to do what you want to do in Java is like this:
1st you define your interface containing a abstract method, that is a method that is not defined yet. Remind that an interface is not a class!
public interface Animal {
public Animal reproduceWith(Animal someAnimal);
}
Then you define the classes that implements the interface and you override the abstract method but now you implement it with the code of your choice. That way the only thing that is the same in the class is the method name. This effectively forces a class to implement a certain method.
public class Dog implements Animal {
@Override
public Animal reproduceWith(Animal someAnimal) {
return new Dog();
}
}
public class Cat implements Animal {
@Override
public Animal reproduceWith(Animal someAnimal) {
return new Cat();
}
}
After that you could for example make a list of MyInterface and iterate over it calling the same method even if its a different class.
List<Animal> list = new ArrayList<Animal>();
list.add(new Cat());
list.add(new Dog());
Animal cat = new Cat();
Animal dog = new Dog();
for (Animal animal : list) {
System.out.println(animal.reproduceWith(cat));
System.out.println(animal.reproduceWith(dog));
}
I hope that helps you out.
来源:https://stackoverflow.com/questions/12232945/use-implementation-type-in-interface-in-java