Subtype dependency on corresponding subtypes

Discussion in 'Java' started by Robert Mark Bram, Aug 12, 2007.

  1. Hi All,

    I have a design question.

    I am writing an application that will search through the contents of
    various files against a given search criteria. I envisage that there
    will be different search strategies, each of which have different
    search criteria. A couple of examples would be as per below.

    Plain Text Strategy. Criteria: a single string (search term), case
    sensitive flag.
    Regular Expression Strategy: a single regular expression, number of
    lines before and after each result to include, case sensitive flag.
    XML Strategy: a single string (search term), name of the xml element
    to be searched within.

    I envisage having an abstract search type and concrete subclasses
    based on each strategy. For example:

    public interface Search {
    SearchResult search(SearchCriteria criteria);
    }

    public class PlainTextSearchStrategy implements Search {
    public SearchResult search(SearchCriteria criteria) {
    // do the search..
    }
    }

    public class RegularExpressionSearchStrategy implements Search
    { ... }

    public class XmlSearchStrategy implements Search { ... }

    My difficulty is the SearchCriteria. Each search strategy type would
    have its own search criteria type and I do not think there is any
    common behaviour (or data) that can be defined in the criteria super
    type. As such, SearchCriteria is just a marker interface, and this
    bothers me. The search strategy sub-types would need to cast
    SearchCriteria to the specific type they need, so there is no type
    safety beyond ensuring the marker interface is implemented. For
    example:

    public class PlainTextSearchStrategy implements Search {
    public SearchResult search(SearchCriteria criteria) {
    PlainTextSearchCriteria ptCriteria = (PlainTextSearchCriteria)
    criteria;
    // do the search..
    }
    }

    Is there a design better suited to this problem of ensuring a sub-type
    can rely on corresponding subtypes being present? As I understand it,
    generics won't help me here either. Do I need to live with the
    casting?

    Any advice would be much appreciated!

    Rob
    :)
     
    Robert Mark Bram, Aug 12, 2007
    #1
    1. Advertising

  2. On Sun, 12 Aug 2007 08:25:06 -0000, Robert Mark Bram wrote:

    > I am writing an application that will search through the contents of
    > various files against a given search criteria.

    [...]
    > Is there a design better suited to this problem of ensuring a sub-type
    > can rely on corresponding subtypes being present? As I understand it,
    > generics won't help me here either. Do I need to live with the
    > casting?
    >
    > Any advice would be much appreciated!


    I am using the following design:

    Abstract_Source maintains the source and the position in the source. The
    interface supports source navigation. Implementations could be:
    String_Soruce, File_Source, GUI_Entry etc.

    Abstract_Scanner is an object that navigates the source. It could be a
    full-blown parser or a simple pattern matcher, like Skip_Blanks,
    Get_Literal, Find_String, Match etc.

    Criteria are properties of a concrete scanner. It knows what it is doing.
    If you want to parametrize a scanner, do not place the parameters in the
    abstract interface of. Do it in a specific constructor / factory. For
    example, a scanner that parses and executes a program in the source has
    lots of parameters (it is table-driven), but these are the business of its
    own.

    --
    Regards,
    Dmitry A. Kazakov
    http://www.dmitry-kazakov.de
     
    Dmitry A. Kazakov, Aug 12, 2007
    #2
    1. Advertising

  3. Robert Mark Bram

    Ed Guest

    On 12 Aug, 10:25, Robert Mark Bram <> wrote:
    > Hi All,
    >
    > I have a design question.
    >

    ....
    > Any advice would be much appreciated!
    >
    > Rob
    > :)




    Three possibilities, in order of decreasing ugliness:

    i) Have all the different criteria reside in the SearchCriteria, so
    that each
    different Search subtype can graze the appropriate parts of the
    SearchCriteria
    object.

    For example, the SearchCriteria could be:

    class SearchCriteria {
    String getSearchTerm() {
    ...
    }

    String getRegularExpression() {
    ...
    }

    int getNumberOfLinesToInclude() {
    ...
    }

    etc.
    }

    Thus, the PlainTextStrategy will call getSearchTerm() but not
    getRegularExpression() and the others, whereas
    RegularExpressionStrategy will
    call getRegularExpression() and getNumberOfLinesToInclude() but not
    getSearchTerm().

    ii) Separate the various SearchCriteria into separate classes such as
    PlainTextCriteria, RegularExpressionCriteria, etc., and create a new
    class,
    CriteriaGroup, whose sole function is to store the various
    SearchCriteria. For
    example:

    class CriteriaGroup {
    void setPlainTextCriteria(PlainTextCriteria criteria) {
    // Store object
    }
    PlainTextCriteria getPlainTextCriteria() {
    return plainTextCriteria;
    }

    void setXmlCriteria(XmlCriteria criteria) {
    // Store object
    }
    XmlCriteria getXmlCriteria() {
    return xmlCriteria;
    }

    etc.
    }

    This will make the Search interface:

    public interface Search {
    SearchResult search(CriteriaGroup criteriaGroup);
    }

    Thus, again, the particular Search subtype will only retrieve the
    appropriate
    criteria; PlainTextStrategy will call
    criteriaGroup.getPlainTextCriteria(),
    etc.

    iii) Item (ii) does rather beg the question: how is the SearchCriteria
    object
    being instantiated in your code today, and why are the instantiation
    of the
    SearchCriteria and Search subtype ojects being instantiated at
    different
    times/locations? If they were being instantiated together then why not
    create
    the Search subtype parameterised with the SearchCriteria it needs,
    perhaps via
    the constructor? (I think this is the solution Mister Kazakov is
    suggesting.)

    There's also a sneaking suspicion that the Search subtype hierarchy is
    unjustified and it is the SearchCriteria itself that holds polymorphic
    interest; perhaps the Search class can be eliminated and the
    SearchCriteria
    can be re-tasked to fill both roles?


    ..ed

    --

    www.EdmundKirwan.com - Home of The Fractal Class Composition
     
    Ed, Aug 12, 2007
    #3
  4. Robert Mark Bram

    H. S. Lahman Guest

    Responding to Bram...

    > I am writing an application that will search through the contents of
    > various files against a given search criteria. I envisage that there
    > will be different search strategies, each of which have different
    > search criteria. A couple of examples would be as per below.
    >
    > Plain Text Strategy. Criteria: a single string (search term), case
    > sensitive flag.
    > Regular Expression Strategy: a single regular expression, number of
    > lines before and after each result to include, case sensitive flag.
    > XML Strategy: a single string (search term), name of the xml element
    > to be searched within.
    >
    > I envisage having an abstract search type and concrete subclasses
    > based on each strategy. For example:
    >
    > public interface Search {
    > SearchResult search(SearchCriteria criteria);
    > }
    >
    > public class PlainTextSearchStrategy implements Search {
    > public SearchResult search(SearchCriteria criteria) {
    > // do the search..
    > }
    > }
    >
    > public class RegularExpressionSearchStrategy implements Search
    > { ... }
    >
    > public class XmlSearchStrategy implements Search { ... }
    >
    > My difficulty is the SearchCriteria. Each search strategy type would
    > have its own search criteria type and I do not think there is any
    > common behaviour (or data) that can be defined in the criteria super
    > type. As such, SearchCriteria is just a marker interface, and this
    > bothers me. The search strategy sub-types would need to cast
    > SearchCriteria to the specific type they need, so there is no type
    > safety beyond ensuring the marker interface is implemented. For
    > example:


    My suggestion would be a variation on Ed's (ii) proposal. The strategy
    subclass defines an algorithm for actually performing the search. That
    algorithm will be generic to the overall type of search. The differences
    between one specific search and another can be expressed in terms of
    parametric data values.

    If one can properly generalize the invariants of the search algorithm
    and cast individual differences as data values, then all the client
    needs to do is provide the data values that are appropriate to the
    particular search (e.g., a string that is interpreted as a plain string
    or a general expression, depending on the strategy).

    However, a more robust solution will separate the concerns of When the
    search needs to be done from the concerns of What algorithm to use and
    the concerns of What specific data values must be supplied for the
    search in hand. (There may also be a need to provide default values for
    some parameters.)

    The conventional way to do this is with a Strategy pattern and a
    Specification object:

    [Client]
    | *
    |
    | R1
    |
    | triggers
    | 1
    [SearchAlgorithm]
    A
    | R2
    +-------------------+---...
    | |
    [RegularExpression] [PlainText]
    | * | *
    | specifies | specifies
    | |
    | R3 | R4
    | |
    | 1 | 1
    [RECriteria] [PTCriteria]
    | |
    +-------------------+----...
    | R5
    _
    V
    [SearchSpecification]

    SearchAlgorithm and the R2 relationship represent the Strategy pattern.
    The R1 relationship is instantiated by whoever understands which
    algorithm needs to be used, which may not be the Client.

    The R3/R4 relationships are instantiated by whoever understands what the
    specific search criteria are. The SearchSpecification objects are just
    dumb data holders for values that express the explicit search criteria
    (strings, line counts, etc.). Those objects can be initialized with
    defaults that are overridden by whoever understands the specific search
    criteria. That may or may not be the Client.

    The advantage is that it allows you to spread responsibilities around
    various objects rather that hard-wiring them all into the Client object,
    which could easily become a god-object if the searching and data
    acquisition are complex and quite different.

    [Note that in your specific example, no subclassing would be needed for
    SearchSpecification because the attribute types would always be the
    same. All that would change would the values (e.g., a string that is a
    regular expression or plain text) and those would be properly
    interpreted by the specific algorithm. Then the relevant relationship is
    directly between SearchSpecification and SearchAlgorithm.]

    Even better, it may be possible to initialize much, if not all, of the
    SearchSpecification from external configuration data. Then you may be
    able to add specific search criteria to the application without touching
    the code. This is a very powerful technique. For <an extreme> example,
    suppose the search algorithm is defined with an XML string sequencing
    operations on data values in the SearchSpecification object. That XML
    string could be just another attribute of SearchSpecification and you
    would not need the Strategy pattern at all. Since the
    SearchSpecification could be defined externally, you could even add new
    algorithms without touching the application code because
    SearchAlgorithm's semantics changes to XMLParser.

    The Invariants and Parametric Polymorphism category on my blog provides
    a number of interesting examples that may be of interest.


    *************
    There is nothing wrong with me that could
    not be cured by a capful of Drano.

    H. S. Lahman

    Pathfinder Solutions
    http://www.pathfindermda.com
    blog: http://pathfinderpeople.blogs.com/hslahman
    "Model-Based Translation: The Next Step in Agile Development". Email
    for your copy.
    Pathfinder is hiring:
    http://www.pathfindermda.com/about_us/careers_pos3.php.
    (888)OOA-PATH
     
    H. S. Lahman, Aug 12, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Daniel Hagen
    Replies:
    3
    Views:
    719
    Oscar kind
    Jul 31, 2004
  2. Marijn
    Replies:
    5
    Views:
    467
    Marijn
    Feb 13, 2004
  3. Crutcher
    Replies:
    1
    Views:
    370
    Alex Martelli
    Dec 31, 2005
  4. Tony Johansson

    LSP and subtypes

    Tony Johansson, Oct 14, 2005, in forum: C++
    Replies:
    1
    Views:
    326
    Regulus
    Oct 14, 2005
  5. red floyd

    C++0x and Enumerated Subtypes

    red floyd, Sep 29, 2006, in forum: C++
    Replies:
    1
    Views:
    303
    mlimber
    Sep 29, 2006
Loading...

Share This Page