1

I was wondering how to design a system in which I have a class Super and a couple of classes that are subclasses of Super (let's say Sub1, Sub2, Sub3) and I want a class Cool. Now there are two things I want to have:

  • Sub1 and Sub2 can be Cool's, Sub3 can never be cool.
  • I must be able to have a List in which there can be Sub1's and Sub2's, if they are cool. If for example I make an object of Sub1 and it is cool I can put it in the list, if it's not it cannot be in the list.

    Any suggestions? Hints?

  • skaffman
    • 398,947
    • 96
    • 818
    • 769
    Samuel
    • 18,286
    • 18
    • 52
    • 88

    6 Answers6

    3

    Maybe something like this:

    class Super {}
    
    interface Cool { boolean isCool(); }
    
    class IsCool implements Cool {
        public boolean isCool() { return true; }
    }
    
    class NotCool impolements Cool {
        public boolean isCool() { return false; }
    }
    
    interface CoolSupporter {
        boolean isCool();
        Cool getCool();
    }
    
    class Sub1 extends Super implements CoolSupporter {
        private Cool cool;
        public Sub1() { this(new NotCool()); }
        public Sub1(Cool cool) { this.cool = cool; }
        public boolean isCool() { this.cool.isCool(); }
        public Cool getCool() { return this.cool; }
    }
    
    class Sub2 extends Super implements CoolSupporter {
        private Cool cool;
        public Sub1() { this(new NotCool()); }
        public Sub1(Cool cool) { this.cool = cool; }
        public boolean isCool() { this.cool.isCool(); }
        public Cool getCool() { return this.cool; }
    }
    
    class Sub3 extends Super {}
    
    class CoolList {
        private List<CoolSupporter> list = new ArrayList<CoolSupporter>();
        public void add(CoolSupporter coolSupporter) {
            if (coolSupporter.isCool()) {
                list.add(coolSupporter);
            } else {
                throw new UncoolException();
            }
        }
    }
    
    Arne Deutsch
    • 14,629
    • 5
    • 53
    • 72
    3

    Arne's answer kind of does what you want, but I find it overly complicated. Maybe I'm missing something? Why not just:

    class Super { }
    
    interface Cool { boolean isCool(); }
    
    class CoolImpl extends Super implements Cool {
        private boolean cool;
        public CoolImpl(boolean cool) { this.cool = cool; }
        public boolean isCool() { return this.cool; }
    }
    
    class Sub1 extends CoolImpl { }
    class Sub2 extends CoolImpl { }    
    class Sub3 extends Super { }
    
    class CoolList extends ArrayList<Cool> {
        public boolean add(Cool cool) {
            if (!cool.isCool()) {
                return false;
            }
            return super.add(cool);
        }
    }
    
    entonio
    • 2,143
    • 1
    • 17
    • 27
    • Seems simpler / neater to me, too – Samuel May 09 '11 at 12:37
    • It's simpler indeed and might be enough in your situation. One point to keep in mind: what if you have a "Cool2" to support ... maybe from "Sub1" and "Sub3". This would not be possible with this approach. – Arne Deutsch May 09 '11 at 13:05
    • I put the logic in CoolImpl just because both Sub1 and Sub2 used it, but one might just forget CoolImpl and copy the logic, and change it as desired, to the relevant subclass(es). But I think the OP is more interested in exploring how the type system may be used, and in that regard the more correct answers the better. I've posted two other approaches below. I don't think either is more or less correct, it's a matter of having the various options. – entonio May 09 '11 at 15:54
    2

    You can create an marker interface say cool. Let class Sub1 and Sub2 implements this interface and before adding to the list check for instance of cool

    may be this can help.

    ponds
    • 2,017
    • 4
    • 16
    • 11
    • Thanks for suggesting but than the subclasses always implement Cool and they cannot not be cool than – Samuel May 09 '11 at 12:00
    1

    You can't have a class optionally belonging to a type in Java. Though you may subclass Sub1, with one subclass implementing an interface Cool and the other not:

    class Super { }
    
    interface Cool { }
    
    class Sub1 extends Super { }
    class Sub1Cool extends Sub1 implements Cool { }
    
    class Sub2 extends Super { }
    class Sub2Cool extends Sub2 implements Cool { }
    
    class Sub3 extends Super { }
    
    class CoolList extends ArrayList<Super> {
        public boolean add(Super sup) {
            if (!(sup instanceof Cool)) {
                return false;
            }
            return super.add(cool);
        }
    }
    

    You might also discard the Cool concept and use a visitor pattern:

    class Super { 
        public boolean addTo(List<Super> coolList) {
            if (canBeAddedToCoolList()) {
                return coolList.add(this);
            }
            return false;
        }
    
        protected boolean canBeAddedToCoolList() {
            return false;
        }
    }
    
    class Sub1 extends Super { 
    
        protected boolean canBeAddedToCoolList() {
            // check logic to allow/disallow addition
        }
    }
    
    entonio
    • 2,143
    • 1
    • 17
    • 27
    0

    IMO, you need to have a overrided List (Say MyList, that overrides add()).

    In add(), Check if the object you are adding is Cool, if it is so, then add it part of the list. If not then just gracefully disregard it.

    Does this help?

    Manimaran Selvan
    • 2,166
    • 1
    • 14
    • 14
    • May be the question is confusing. Did I understand your question right? – Manimaran Selvan May 09 '11 at 11:55
    • Thank you for your participation :) a parameterized list will as such only accept parameters of the type cool, what i try to find out is how I can design my subclasses so that they can or cannot implement cool – Samuel May 09 '11 at 11:59
    • Is Cool an interface? It is not the Super class right? (As mentioned in the question) – Manimaran Selvan May 09 '11 at 12:12
    • Still not clear actually. What is the condition based on which you decide to implement or not! Are you building this class on runtime using velocity or jet template of that sort? – Manimaran Selvan May 09 '11 at 12:16
    • The user of the software can decide wether a subclass should be cool or not. For example: I have a house, subclasses: bungalow etc and now I some houses can implement the GarageHouse interface. But the classes who can implement it don't have to implement it. But after a user entered houses into my system I want to be able to make for example lists of GarageHouses. (it might be a stupid example but I hope it clarifies it a little) – Samuel May 09 '11 at 12:43
    • Are you expecting something like this? - if(some condition) { Sub1 implements Cool {}} else {Sub1{}} .. Like conditional compilation in C/C++? – Manimaran Selvan May 09 '11 at 13:55
    • If that is the one, I don't think that is possible through direct support! You might have to use reflection, templating engines etc to get that done. Its pretty complex! – Manimaran Selvan May 09 '11 at 13:56
    • What do you mean with reflection? And it shouldn't be a runtime solution :/ – Samuel May 09 '11 at 20:50
    • You have clearly said that the functionality is decided by the user of the software! It clearly states that it is a runtime problem! Isn't it so? – Manimaran Selvan May 10 '11 at 07:15
    • I obviously didn't specify enough, by the user i don't mean a human user, but a client who uses my classes in his software. – Samuel May 10 '11 at 07:19
    • A library kind of thing! I understand - just saw the thread completely. You already got the answer it seems :-) Happy coding.. – Manimaran Selvan May 10 '11 at 07:20
    • Thank you, and i'm glad seeing you got so involved in it :) – Samuel May 11 '11 at 16:00
    0

    The simplest way you can manage this is to further subclass Sub1 (CoolSub1 and NotCoolSub1) and Sub2 (CoolSub2 and NotCoolSub2).

    CoolSub1 and CoolSub2 can then implement Cool ( Cool should be an interface and not a class)

    You can then define

    List<Cool>
    

    which will accept implementations of Sub1 and Sub2, but only if they implement Cool.

    pgbsl
    • 222
    • 1
    • 3