Redesign the OOP Splitting combined interfaces to individuals

丶灬走出姿态 提交于 2019-12-12 03:00:05

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!