Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a specific way to give a certain subclass some functions of the superclass?

The Problem

I'm trying to create an application where an object class can implement some operations from the total pool of available operations. The end goal is to not have any code duplication and to abide by the laws of OOP as much as possible.

In more detail, I'm trying to make a search engine using Lucene. Lucene
uses many indices. I've already implemented a simple structure where different index-objects inherit the methods of a parent class. The problem is that, whatever method is implemented in that parent class, it automatically becomes available for all subclasses to use. I want to give the option to the user to determine if he wants to do a phrase search, a term search or whatever else there is available for that specific index. The catch is, some indices shouldn't have the option to conduct phrase search, for example.

First Thoughts

I've thought of implementing something close to the Composite pattern,
as described by the GoF. I would implement the search operations (e.g. term search, phrase search) as primitive operations implementing some Component class and add these primitive objects later on to a Composite object. The Composite object will be implementing the same Component class as the primitives.

public abstract class Index {
    public Index(String indexPath) {
        // Constructor using the information provided by the subclass
    }

    public void phraseSearch(...) {
         // Do the operation
    }

    public void termSearch(...) {
        // Do the operation
    }

    public void categorySearch(...) {
        // Do the operation
    }
}

public class ReviewIndex extends Index {
    public ReviewIndex() {
        super("./review_index/");
    }
}

public class TipIndex extends Index {
    public TipIndex() {
        super("./tip_index/");
    }
}

Expected Outcome

The class ReviewIndex shouldn't be able to perform a categorySearch but be
able to execute phraseSearch and termSearch. Respectively, the TipIndex class
should be able to execute some of the parent class methods.

Final Thoughts

I know that in my solution there is no code duplication but there are useless methods being generated each time a new index object is created. Thank you all in advance!

P.S. If you think the Composite pattern is the way to go, in which way would you actually add the primitive objects to the composite class and in which way would you invoke them when need to?

like image 678
Invalid_Path Avatar asked Jul 03 '19 14:07

Invalid_Path


Video Answer


2 Answers

All methods defined in a superclass are available at deriving classes but with Java 8 you might be able to get something like this by using default-methods in interfaces. So instead of one abstract class containing all possible methods you might implement four interfaces

public interface Searchable {
    public String getIndexPath();
}

public interface PhraseSearchable extends Searchable {
    public default void phraseSearch() {
        String indexPath = getIndexPath();
        // do the search
    }
}

public interface TermSearchable extends Searchable {
    public default void termSearch() {
        String indexPath = getIndexPath();
        // do the search
    }
}

public interface CategorySearchable extends Searchable {
    public default void categorySearch() {
        String indexPath = getIndexPath();
        // do the search
    }
}

To avoid duplicate code you can create an abstract class

public abstract class AbstractSearchable implements Searchable {
    private String indexPath;

    public AbstractSearchable(String indexPath) {
        this.indexPath = indexPath;
    }

    // other methods that might be useful
}

Your actual classes can then implement the corresponding interfaces

public class ReviewIndex extends AbstractSearchable implements CategorySearchable {
    public ReviewIndex() {
        super("./review_index/");
    }
}
public class TipIndex extends AbstractSearchable implements PhraseSearchable, TermSearchable {
    public ReviewIndex() {
        super("./review_index/");
    }
}

If this is possible depends heavily on the actual implementation of the search methods. Interfaces can't contain any members, etc. so these methods must be able to run for themselves (like a static method without using any static members of the class). You might to overcome this problem by adding more methods to the Searchable interface that provide the data and do the implementation in the abstract class but that might expose internal stuff to the public because all the declared methods in an interface are public.

like image 60
Lothar Avatar answered Oct 13 '22 17:10

Lothar


If you don't want to use categorySearch(...) for ReviewIndex class then create one more hierarchy where you keep the categorySearch(...) method.

Example:

public abstract class Index {
    public Index(String indexPath) {
        // Constructor using the information provided by the subclass
    }

    public void phraseSearch(...) {
         // Do the operation
    }
}

// Give a meaningful Name
public abstract class IndexChild1 extends Index {
    public void categorySearch(...) {
        // Do the operation
    }
}

// Give a meaningful Name 
public abstract class IndexChild2 extends Index {
     public void termSearch(...) {
            // Do the operation
     }
}

public class ReviewIndex extends IndexChild1 {
    public ReviewIndex() {
        super("./review_index/");
    }
}

public class TipIndex extends IndexChild2 {
    public TipIndex() {
        super("./review_index/");
    }
}
like image 45
Pradyskumar Avatar answered Oct 13 '22 18:10

Pradyskumar