Search code examples
java-8solid-principlessingle-responsibility-principleopen-closed-principle

Open / Closed Principle & Single Responsibilty -- Graphs


I am coding a Graph exploration program and have hit a bit of a stumbling block.

My graph is made up of Vertex and NetworkLink objects, and can be obatined by querying a GeographyModel object.

The idea is List<NetworkLink> is retrieved from the GeographyModel and then supplied to a MetaMap to get the required additional information.

What I want to do is try and adhere to the Open / Closed Principle by adding information each NetworkLink by creating MetaMap objects, but have somewhat got my knickers in a twist as to how to do this!

Below is the code for the MetaMap.

public class MetaMap<T> {

private final String name;
private final Map<NetworkLink, List<T>> metaData;
private final Map<T, Set<NetworkLink>> reverseLookup;
private final List<T> fallback;
private final List<T> information;

public MetaMap(String name, T fallback){
    this.name = name;
    this.metaData = new HashMap<>();
    this.reverseLookup = new HashMap<>();
    this.fallback = new ArrayList<>();
    this.fallback.add(fallback);
    this.information = new ArrayList<>();
}

/**
 * Returns an identifier giving the information contained in this map
 *
 * @return
 */
public String getName() {
    return name;
}

/**
 * Marks from origin to destination with information of type T
 *
 * @param line
 * @param information
 */
public void markLineFragment(RunningLine line, T information) {
    line.getLinks().stream().map((link) -> {
        if(!metaData.containsKey(link)) {
            metaData.put(link, new ArrayList<>());
        }
        return link;            
    }).forEach((link) -> {
        metaData.get(link).add(information);
    });

    if(!reverseLookup.containsKey(information)) {
        reverseLookup.put(information, new HashSet<>());
    }

    reverseLookup.get(information).addAll(line.getLinks());
}

/**
 * Returns the information on the given NetworkLink
 *
 * @param link
 * @return
 */
public List<T> getInformation(NetworkLink link) {
    return metaData.getOrDefault(link, fallback);
}

/**
 * Returns the information associated with the given line fragment
 * @param line
 * @return 
 */

public List<T> getInformation(RunningLine line) {
    Set<T> resultSet = new HashSet();

    line.getLinks().stream().forEach((link) -> {
        List<T> result = getInformation(link);

        resultSet.addAll(result);
    });

    return new ArrayList<>(resultSet);
}

/**
 * Returns all of the matching links which match the given information
 * @param information
 * @return 
 */

public List<NetworkLink> getMatchingLinks(T information) {
    return new ArrayList<>(reverseLookup.get(information));
}

public void addInformation(T info) {
    information.add(info);
}

public void removeInformation(T info) {
    information.remove(info);
}

Now... the problem I have is that as I expand the program, each new part will require a new MetaMap which is derived from GeographyModel.

I want to follow the OCP and SRP as I am adding capabilities the program, but get a touch stuck as to implementation / combining the two concepts. A couple of thoughts do occur...

I could get each new model requiring a MetaMap to register itself with the GeographyModel, but fear I would be violating the SRP. Each new prgoram feature could own a MetaMap and maintain it, but that would require querying the GeographyModel in the first place.

Any ideas how I could approach this?


Solution

  • Why would you want to implement OCP? What problems are you trying to solve? If you implemented OCP only because of everyone else thought it was good I strongly recommend you to think twice.

    Each principle in SOLID / GRASP as well as design patterns are guild-lines and solutions for a very specific kind of problems. Basically they are tools. You should identify your problems first, state them as clearly as possible. They you will be able to pick the right tools to deal with them.

    Blindly implementing SOLID / GRASP or design patterns is much like using a hammer for cooking food. If you were lucky enough you might success but we both know that the probability was very low.

    https://www.u-cursos.cl/usuario/777719ab2ddbbdb16d99df29431d3036/mi_blog/r/head_first_design_patterns.pdf

    Please navigate to page 125/681 (on the top bar) and read the entire page!