javaoop

How to make a one method reusable instead of two methods?


I asked a similar question earlier today, but now I am told that the requirements have changed.

I have 3 classes - Product, ProductOffering (PO) and ProductOfferingLists (POL). Product contains PO, and PO contains POL. All those classes extend an abstract class called CMS.

I want to attach PO to P, and POL to PO, but I am looking for a re-usable method, since the logic is identical, except for the class names.

Unfortunately, my tester class is requiring two methods, and the hierarchy classes are requiring a cast to fulfill the abstract CMS contract.

This is driving me nuts. How can I make this more reusable, so I don't have multiple methods and casting?

package puzzler;
import java.util.ArrayList;
import java.util.List;

public class Tester {
    public static void main(String[] args) {
        Product p = new Product();
        PO pa = new PO();
        POL po = new POL();

        List<PO> lpa = new ArrayList<PO>();
        List<POL> lpo = new ArrayList<POL>();

        attachChildToParent(lpa, p);
        attachChildToParent(lpo, pa);
    }

    static void attachChildToParent(List<PO> listChild, Product parent) {
        for (PO po : listChild) {
            parent.attach(po);
        }
    }

    static void attachChildToParent(List<POL> listChild, PO parent) {
        for (POL po : listChild) {
            parent.attach(po);
        }
    }
}

The CMS Class:

package puzzler;

abstract class CMS {
    abstract void attach(CMS childNode);
}

Product Class - the top of the hierarchy that owns PO:

package puzzler;
import java.util.List;

public class Product extends CMS {
    List<PO> lpo;

    public List<PO> getLpo() {
        return lpo;
    }

    public void setLpo(List<PO> lpo) {
        this.lpo = lpo;
    }

    @Override
    void attach(CMS childNode) {
        this.getLpo().add((PO)childNode);
    }
}

Product Offering, owned by Product and in turn owns a Product Offering List

package puzzler;
import java.util.List;

public class PO extends CMS {
    List<POL> lpol;

    public List<POL> getLpo() {
        return lpol;
    }

    public void setLpo(List<POL> lpol) {
        this.lpol = lpol;
    }


    @Override
    void attach(CMS childNode) {
        this.getLpo().add((POL)childNode);
    }
}    

Product Offering List (POL) owned by PO

package puzzler;

public class POL extends CMS {
    @Override
    void attach(CMS childNode) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

Solution

  • (Java 7 syntax used, but easy to adapt for Java 6)

    Define your CMS class as follows:

    public abstract class CMS<C extends CMS<?>> {
        public abstract void attach(C childNode);
    }
    

    Then your Product class can look like this:

    public class Product extends CMS<PO> {
        private List<PO> lpo = new ArrayList<>();
    
        public List<PO> getLpo() {
            return lpo;
        }
    
        public void setLpo(List<PO> lpo) {
            this.lpo = lpo;
        }
    
        @Override
        public void attach(PO childNode) {
            getLpo().add(childNode);
        }
    }
    

    Then your PO class can look like this:

    public class PO extends CMS<POL> {
        private List<POL> lpol = new ArrayList<>();
    
        public List<POL> getLpo() {
            return lpol;
        }
    
        public void setLpo(List<POL> lpol) {
            this.lpol = lpol;
        }
    
        @Override
        public void attach(POL childNode) {
            getLpo().add(childNode);
    
        }
    }
    

    Then your POL class can look like this:

    public class POL extends CMS<CMS<?>> {
        @Override
        public void attach(CMS<?> child) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
    

    And finally, your Tester class can look like this:

    public class Tester {
          public static void main(String[] args) {
                Product p = new Product();
                PO po = new PO();
    
                List<PO> pos = new ArrayList<PO>();
                List<POL> pols = new ArrayList<POL>();
    
                attachChildToParent(pos, p);
                attachChildToParent(pols, po);
            }
    
        private static <C extends CMS<?>> void attachChildToParent(List<C> childNodes, CMS<C> parent) {
            for (C childNode : childNodes) {
                parent.attach(childNode);
            }
        }
    }
    

    Only one method needed, no casts.