2

I have an interface, Attribute, that is going to be implemented in various ways,

class AttributeA implements Attribute{\\..}
class AttributeB implements Attribute{\\..} 

Then I'm planning to have a class containing a list of interface members

class Example { 
    List<Attribute> attributes;
    //..
} 

And then I'm planning to have a class containing a list of those

class ExamplesAndMore { 
    List<Example> examples;
    //..
} 

But, I want any instatiation of ExamplesAndMore to make sure that it only takes examples of the same type or signature. That is, I want to make sure the examples list doesn' t contain one member whose attributes list is of the form <AttributeA, AttributeA, AttributeB> while another is of the <AttributeA, AttributeA, AttributeA> or <AttributeA, AttributeA, AttributeB, AttributeB>.

I could just check everywhere I modify the examples list.

A comment asked me to be more specific, so I'll give code for how I could do this.

class Example { 
    List<Attribute> attributes;

    public List<Class<? extends Attribute>> getSignature(){
        List<Class<? extends Attribute>> result = new ArrayList<Class<? extends Attribute>>();
        for(Attribute attribute : attributes){
            result.add(attribute.getClass());
        }

        return result;
    }

    //..
}

public class ExamplesAndMore {
    List<Example> examples;
    List<Class<? extends Attribute>> signature;

    public ExamplesAndMore(List<Class<? extends Attribute>> signature){
        this.signature = signature;
        this.examples = new ArrayList<Example>();
    }

    public void addExample(Example example){
        if(!example.getSignature().equals(signature)){
            throw new IllegalArgumentException(String.format("This takes examples with signature %s", signature.toString()));
        }
        examples.add(example);
    }

    //..
}

But I wonder if this is a good way of going about this, checking for types at runtime doesn't feel nice. Basically I think this code smells a bit. One way this smell might manifest as an actual problem is when I create

class GenericAttribute<T> implements Attribute{\\..}  

with the intention of not having an example with an attribute of type GenericAttribute<ClassA> and one of type GenericAttribute<ClassB> in the same list. Then type erasure ruins my day.

Also, when I don't need examples to contain arbitrarily many attributes but only a fixed number (say 3), then my problem goes away entirely and I can even check at compile-time by having

class Example<T1, T2, T3> { 
    //..
}

public class ExamplesAndMore<T1,T2,T3> {
    List<Example<T1,T2,T3> examples;

    public void addExample(Example<T1,T2,T3> example){\\..}
    //..
}

However this approach obviously doesn't extend to examples with arbitrarily many attributes.

Anyway, I feel that I'm missing some obvious technique or something. Is there a nice pattern that deals with this, am I designing this badly? Chances are I'm not the first one doing this.

Also sorry for the lousy title, If I had a better description for my problem I'd probably have better luck searching for an answer and wouldn't have to ask...

5
  • 6
    Instead of worrying about "what design pattern", focus your question on the specific problem you have (or don't have). Design patterns are just another tool to simplify communicating what a section of code does. Not everything needs to be labeled as a design pattern.
    – user53019
    May 26, 2015 at 12:05
  • @GlenH7 "Design patterns are just another tool to simplify communicating what a section of code does." I agree but I'd also add that they are also common consensus good ways of solving a specific problem. I figured a well known one might be applicable here. I can and will implement my "could just check everywhere" solution and edit my question. Maybe that makes it a better question? If not, any other advice as to how to ask a "how do I do this in a nice structural way"-question? Are they just not appreciated here?
    – Hirle
    May 26, 2015 at 13:20
  • 3
    Looking for a pattern instead of solving the problem is a fool's errand. Please edit your question to focus on the specific problem you have with your code, and you are more likely to receive a meaningful answer. You've already laid out most of your real problem in your previous comment. Use that as the base and explain what's not working for you currently.
    – user53019
    May 26, 2015 at 13:39
  • @GlenH7 So... I edited in my "could just check everywhere"-solution and edited the question to reflect that. But I somehow wonder if that made it a better question. I'm still just asking "is this a good way of going about things", there is nothing that is not working (as far as I can tell). That's because my question is not of that type. I understand your critique that is based in "Ask specific problems, because those are well suited for Q&A". But I also think you can see what my question is and see that it is just not that specific.
    – Hirle
    May 26, 2015 at 14:06
  • 3
    Why do you need those elements of the lists to be of the same types and lengths?
    – null
    May 26, 2015 at 19:55

2 Answers 2

2

It seems slightly odd that Example.attributes can contain a mixture of AttributeA and AttributeB objects, but ExamplesAndMore.examples must contain a 'homogenous' (using that loosely) List of Example objects. How are these supposed to be used, for both Example and ExamplesAndMore classes? Is there also some kind of implied ordering/equivalence between the entries of ExamplesAndMore.examples? Could that be another code-smell?

Staying on topic though, you may want a method inside Example that can reasonably describe the contents of itself... this can be as simple as concatenating the class names of its own entries, as illustrated below. I think that is safe enough since List have a predictable iteration order.

public String getEntriesDescription() {
    return attributes.stream().map(v -> v.getClass().getName())
                        .collect(Collectors.joining(";"));
}

When you are adding an Example object to ExamplesAndMore, you can use that to perform the comparison you want...

public void addExample(Example example) {
    // assuming you have a field exampleDescription
    if (!exampleDescription.equals(example.getEntriesDescription()) {
        throw new IllegalArgumentException("Example description does not match.");
    }
    examples.add(example);
}

This is quite similar to what you have in mind.

0

If class AttributeA implements Attribute and class AttributeB implements the same, that means: in some respect AttributeA behaves like AttributeB; and the abstraction level on which they do that, is behaving like Attribute. This is how polymorphism works!

But, I want any instatiation of ExamplesAndMore to make sure that it only takes examples of the same type or signature.

The correct way of implementing this - according to your initial design would be to have a separate class of Example which has a List of Attributes of one kind, i.e. you need another Interface for Example which allows to distinguish between Example containing AttributeA and Example containing AttributeB. Then you are a) sure, that the concrete Example contains only the attributes you wanted and b) could use the abstraction of the interface to treat them the same in this respect.

In the end, you could define your ExamplesAndMore class, like intended: containing Examples, but not classes, but rather interfaces.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.