Updating a subclass with a superclass

Description of the problem

I have an abstract class Paper

that contains the general properties of all documents and one or more child paper classes that add additional information for that paper type. Then I have HashMap<String, Paper>

to store several documents.

My app allows the user to update the paper by providing pid

and then supplying the attributes and values ​​to update. The problem I'm running into is how to update properties in subclasses when all I have is the superclass.

What is the best way / practice to deal with this situation?

Class structure

public abstract class Paper {
    String pid;
    String title;
    String author;
}


public class Publication extends Paper {
    int pages;
}

public class PHDThesis extends Paper {
    String supervisor;
}

      


My current attempt

This is what I have ** and it works with instance of

; but I believe there must be a better way to do this.

import java.util.*;

public class App {
    public static abstract class Paper {

        private String title;
        private String author;

        public Paper(String title, String author) {
            this.title = title;
            this.author = author;
        }

        public void update(String title, String author) {
            this.title = title;
            this.author = author;
        }
    }


    public static class Publication extends Paper {

        private int pages;

        public Publication(int pages, String title, String author) {
            super(title, author);
            this.pages = pages;
        }

        public void update(String title, String author, int pages) {
            super.update(title, author);
            this.pages = pages;
        }

    }

    public static class PHDThesis extends Paper {

        private String supervisor;

        public PHDThesis(String supervisor, String title, String author) {
            super(title, author);
            this.supervisor = supervisor;
        }

        public void update(String title, String author, String supervisor) {
            super.update(title, author);
            this.supervisor = supervisor;
        }
    }

    public static void main(String[] args) {
        HashMap<String, Paper> papers = new HashMap<String, Paper>();

        papers.put("P001", new PHDThesis("My Super", "My PHD Title", "My Author"));
        papers.put("P002", new Publication(22, "My Pub Title", "My Author"));

        Paper p = papers.get("P001");

        if (p instanceof PHDThesis) {
            ((PHDThesis)p).update("New Title", "New author", "New Super");
        } else if (p instanceof Publication) {
            ((Publication)p).update("New Title", "New author", 33);
        }
    }
}

      

** minified test code, actual code is much more complex and better laid out.

+3


source to share


4 answers


You can create an object named UpdateBundle using getters for each attribute.

The Paper class will then have a method update (UpdateBundle) that each child will implement differently.

All you have to do is call this method for each child and they will know how to handle it.



On a separate note, I don't understand why the paper class is abstract. You don't seem to have abstract methods.

public abstract class Paper {
    String pid;
    String title;
    String author;

    public void update(PaperUpdateBundle bundle)
    {
        pid = bundle.getPID();
        title = budnle.getTitle();
        author = bundle.getAuthor();
    }
}


public class Publication extends Paper {
    int pages;

    public void update(PaperUpdateBundle bundle)
    {
       super.update(bundle);
       pages = bundle.getPages();
    }
}

public class PHDThesis {
    String supervisor;


    public void update(PaperUpdateBundle bundle)
    {
       super.update(bundle);
       supervisor = bundle.getSupervisor();
    }
}

public interface PaperUpdateBundle
{
    String getPID();
    String getTitle();
    String getAuthor();
    int getPages();
    String getSupervisor();
}

      

+3


source


Create Method

public void update( Map<String, Object> parameters );

      

to all docs and pull the appropriate properties out of it in Paper implementations.



In a post, it might look like this:

public void update( Map<String, Object> parameters ) {
  super.update( parameters );

  this.pages = parameters.get( "pages" );
}

      

+2


source


I asked a similar question a long time ago, the answers to this question might help you,

Naive inheritance problem - Java

Good luck!

+2


source


The problem with the accepted answer is that it requires you to manually update all the properties. If the property list changes, you must change the update () method, otherwise the situation will become out of sync. In my experience, this happens a lot. And then you have to spend a lot of time trying to track down the error.

Another way (I won't call it the "best" way) is to use reflection or some third party library to copy the fields. There are some trade-offs, however. The advantage is that your code requires much less work and is likely to have fewer bugs. The downside is that your code will be slower, less flexible, and will not check compile times.

I've sometimes used Jackson ObjectMapper.convertValue () for this. You can find other ways to do this here: Copy all values ​​from fields to one class to another via reflection .

0


source







All Articles