简体   繁体   中英

Interface implementation and common function

I have the following requirement,

  • There will be 2(or more) different classes to perform same kind of operation(in different ways). Therefore I decided to create an interface. Then I implemented these 2 classes with my interface.
  • Now, from another class I will be using the object of type Interface and calls functions. Everything works fine.
  • Then a new requirement came to create a common functionality that applies to both classes.
  • I don't want to define same function in both classes. And interface dont allows function definition.
  • First I thought abstract class will be useful. Because it allows function definition and abstract functions. But abstract classes cant be instantiated and also I need to create objects with individual class types.

Sorry I cant find a simple way to define my problem. It feels like a solution that spring framework provides. But I need to know how to acheive this from a Java/C# application.

It sounds like you want an abstract class implementing the common functionality, but still have two concrete classes for the distinct functionality. You may or may not still want to keep the interface as well. So the options are:

        Interface
            ^
            |
         Abstract
          class
            ^
           / \
   Concrete   Concrete 
   class 1    class 2

or just

         Abstract
          class
            ^
           / \
   Concrete   Concrete 
   class 1    class 2

Code which wants to use these classes just uses the interface or abstract class. How you configure which concrete class to use were will depend on your exact requirements - but presumably you'd already tackled that in the earlier version.

A common pattern for this is:

  1. Define the interface (as you've done).
  2. Create an abstract class which implements the common functionality in terms of the non-common functionality.
  3. Extend this abstract class to provide the non-common functionality.

A lot of JDK classes do this. For instance, the List<T> interface has an AbstractList<T> abstract class, which is extended to provide both ArrayList<T> and LinkedList<T> .

A simple (if contrived) example would be something like:

interface IntThingy {
    int getValue();
    int getDoubeValue();
}

abstract class AbstractIntThingy implements IntThingy {
    @Override
    public int getDoubleValue() {
        return getValue() * 2;
    }
}

class ConstantFourtyTwo extends AbstractIntThingy {
    @Override
    public int getValue() {
        return 42;
    }
}

class ConstantIntThingy extends AbstractIntThingy {
    private final int value;

    ConstantIntThingy(int value) {
        this.value = value;
    }

    @Override
    public int getValue() {
        return value;
    }
}

Note that once Java 8 arrives, you'll be able to define methods in interfaces. These are commonly known as "defender methods." When that happens, you may not need the abstract class -- depending on whether that common functionality needs to maintain its own state (interfaces still won't be able to define instance state). But for now, the interface-abstract-concrete pattern often works well.

You can try to avoid using simple interface and use strategy pattern:

http://en.wikipedia.org/wiki/Strategy_pattern

Create a concrete class (or better abstract class) that implements your interface, and contains your "common functionality", Now you can extend this class (Hierarchy) with two (or more) classes.

there are many more ways of designing this requirement. And I am not sure If mine is best either.

Just to add on to Jon Skeet's answer, you need to think as to what kind of relationship your classes have with the interface or the intended abstract class. If the relationship is between the behaviour laid out in the interface is has-a then the interface is the right choice, and if it is an is-a relationship, you can go with an abstract class.

In another scenario, you can also check if the relationship is has-a, and the new common functionality that you want to implement is an is-a relationship, then apart from option by Jon, you can use something like this:

           Abstract
            class
              ^
             / \
Interface            Interface
     \                /    
     Concrete   Concrete 
     class 1    class 2

for eg:

interface IParent{}

abstract class Parent{}

class Child1: Parent, IParent{}

class Child2: Parent, IParent{}

It all depends how you design your classes for future use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM