问题
I was trying to understand how to avoid double entry in a clean and "designable" way to the following scenario:
public interface ICommandAble
{ }
public interface ILogAble extends ICommandAble
{ }
public interface IMonitorAble extends ICommandAble
{ }
public abstract class ClassAbs
{ }
public class A extends ClassAbs implements IMonitorAble, ILogAble
{ }
Test method:
public void test()
{
A a=new A();
List<ICommandAble>commandList=new ArrayList<ICommandAble>()
if (a instanceof ILogAble)
{
ILogAble logAbleItem=(ILogAble)a;
commandList.add(logAbleItem);
}
if (a instanceof IMonitorAble) {
IMonitorAble monitorAbleItem=(IMonitorAble)a;
commandList.add(monitorAbleItem);
}
for(ICommandAble item: commandList)
{
if(item instanceof IMonitorAble)
{
log.debug("is monitorable");
}
if(item instanceof ILogAble)
{
log.debug("is logable");
}
}
the output is:
2013-04-22 18:25:00,498 com... [DEBUG] is monitorable
2013-04-22 18:25:02,150 com.... [DEBUG] is logable
2013-04-22 18:25:08,322 com.... [DEBUG] is monitorable
2013-04-22 18:25:08,977 com.... [DEBUG] is logable
That will cause my program to do double executions for each "xAble"
I expected to see:
2013-04-22 18:25:00,498 com... [DEBUG] is monitorable
2013-04-22 18:25:02,150 com.... [DEBUG] is logable
How should I redesign this(in a clean way) that the second iterator conditionion will be based on the reference type and not on the instance type. getting something like this:
2013-04-22 18:25:00,498 com... [DEBUG] is monitorable
2013-04-22 18:25:02,150 com.... [DEBUG] is logable
- Think that in the future I might have additional "ables"
Thanks, ray.
回答1:
If you are testing objects to see if they are instances of interfaces then they must implement that interface. They can always implement other interfaces too. In your scenario, to achieve the output you need you must make the objects only implement one of the two interfaces.
public class Test {
public interface ICommandAble {
}
public interface ILogAble extends ICommandAble {
}
public interface IMonitorAble extends ICommandAble {
}
public abstract class ClassAbs {
}
public class A extends ClassAbs implements IMonitorAble, ILogAble {
}
public class B extends ClassAbs implements IMonitorAble {
}
public class C extends ClassAbs implements ILogAble {
}
public void test() {
A a = new A();
B b = new B();
C c = new C();
List<ICommandAble> commandList = new ArrayList<ICommandAble>();
commandList.add(a); // Remove this line to just get the two printouts.
commandList.add(b);
commandList.add(c);
for (ICommandAble item : commandList) {
if (item instanceof IMonitorAble) {
System.out.println(item.getClass().getSimpleName() + " is monitorable");
}
if (item instanceof ILogAble) {
System.out.println(item.getClass().getSimpleName() + " is logable");
}
}
}
public static void main(String args[]) {
new Test().test();
}
}
prints
A is monitorable
A is logable
B is monitorable
C is logable
I have added an A
to the list too to demonstrate the difference.
回答2:
As you are only adding items to an List
, you can change your code to verify if it is an instance of ICommandAble
, like this:
if (a instanceof ICommandAble) {
commandList.add(a);
}
回答3:
It's because your adding a
into the commandList twice, once for being loggable and again for being monitorable.
You should combine the 2 if statements into 1:
if (a instanceof ILogAble || a instanceof IMonitorAble)
{
commandList.add(a);
}
回答4:
Add the instances to a hashset not a list so that an instance would be present once even if it added more than once
回答5:
As the other answers already explained, what you want is not possible with casting. You will need to use multiple lists. You can organize this lists in a Map to make it more maintainable, but maybe you should rethink your design.
Here a way how you could easily use multiple lists:
public interface ICommandAble {}
public interface ILogAble extends ICommandAble {}
public interface IMonitorAble extends ICommandAble {}
public abstract class ClassAbs {}
public class A extends ClassAbs implements IMonitorAble, ILogAble {}
public List<ICommandAble> getList(LinkedHashMap<Class<? extends ICommandAble>, List<ICommandAble>> commandList,
Class<? extends ICommandAble> clazz) {
if (commandList.get(clazz) != null)
return commandList.get(clazz);
ArrayList<ICommandAble> l = new ArrayList<>();
commandList.put(clazz, l);
return l;
}
public void test() {
A a = new A();
LinkedHashMap<Class<? extends ICommandAble>, List<ICommandAble>> commandList = new LinkedHashMap<>();
if (a instanceof ILogAble)
getList(commandList, ILogAble.class).add(a);
if (a instanceof IMonitorAble)
getList(commandList, IMonitorAble.class).add(a);
for (Class<? extends ICommandAble> clazz : commandList.keySet())
for (ICommandAble item : commandList.get(clazz)) {
if (clazz.equals(IMonitorAble.class))
log("is monitorable");
if (clazz.equals(ILogAble.class))
log("is logable");
}
}
来源:https://stackoverflow.com/questions/16156241/redesign-the-oop-splitting-combined-interfaces-to-individuals