Teaser Image

qnoid

Markos Charatzas - London, UK




    public class Psychiatrist
    {
        private final Pharmacy pharmacy;

        private Psychiatrist(Pharmacy pharmacy)
        {
            this.pharmacy = pharmacy;
        }

        public Prescription takeCare(MultiplePersonality personality)
        {
            // MultiplePersonality may have been created with a 
            // String, Integer or just a Boolean

            // try to get a String from MultiplePersonality object
            String string = personality.areYouAString();
            if (string != null) {
                this.pharmacy.isAString(string);
                return this.pharmacy.getPrescription();
            }

            // or try to get an Integer from MultiplePersonality object
            Integer integer = personality.areYouAnInteger();
            if (integer != null) {
                this.pharmacy.isAnInteger(integer);
                return this.pharmacy.getPrescription();
            }

            // or try to get just a Boolean from MultiplePersonality object
            Boolean nuts = personality.areYouNuts();
            if (nuts == null) {
                throw new RuntimeException();
            }
            
        return null;        
        }
    }

    /**
     * Instead use this
     */

    public class Psychiatrist
    {
        private final Pharmacy pharmacy;

        private Psychiatrist(Pharmacy pharmacy)
        {
            this.pharmacy = pharmacy;
        }

        public Prescription takeCare(Personality personality) {
        return this.pharmacy.getPrescription(personality);        
        }
    }

    public class Pharmacy
    {
        public void isAString(String string)
        {

        }

        public void isAnInteger(Integer integer)
        {

        }

        public Prescription getPrescription(Personality personality)
        {
            personality.whatAreYou(this);

            //decide upon prescription
        }
    }

    /**
     * With a Personality for each
     */
    public class IntegerPersonality implements Personality
    {
        private final Integer integer;

        private IntegerPersonality(Integer integer)
        {
            this.integer = integer;
        }

        @Override
        public void whatAreYou(Pharmacy pharmacy) {
            pharmacy.isAnInteger(this.integer);
        }
    }

    public class StringPersonality implements Personality
    {
        private final String string;

        private StringPersonality(String string)
        {
            this.string = string;
        }

        @Override
        public void whatAreYou(Pharmacy pharmacy) {
            pharmacy.isAString(this.string);
        }
    }

    public class SanePersonality implements Personality
    {
        @Override
        public void whatAreYou(Pharmacy pharmacy) {
            throw new RuntimeException("I'm sane!");
        }
    }

Don't try to do to much. (Class Relationships). Identify polymorphism in 3 steps. (How to identify polymorphism)?

  • find the common operation (e.g. #whatAreYou)
  • find how is every operation different and put it in a method in each own class (e.g. #isAString, #isAnInteger, "is nuts")
  • introduce an interface for the above classes with that common method

That's all really. Try it with a Calculator example now.

Using polymorphism will

  • eliminate the need for multiple if(s)
  • eliminate the check for null
  • eliminate the exceptional case (in this case to return null)

Plus on each Personality class you get

  • final fields
  • single responsibility
  • encapsulation

Disclaimer: This is actual (disguised) code as seen on a very popular API. There are even more problems to discuss about it but let's just focus on one thing at a time.