Avoiding generic types of form Foo>

后端 未结 2 413
北荒
北荒 2020-12-11 15:50

I frequently find myself wanting to write generic class definitions of the form

public class Foo

        
相关标签:
2条回答
  • 2020-12-11 16:37

    I would recommend that we simply use <This> to represent the "self type". No need for bound, since it looks complicated, doesn't deliver the intention, and cannot enforce the constraint anyway.

    public class Foo<This> {
    
        private final List<ChangeHandler<This>> handlers = new ArrayList<>();
    
        public void addChangeHandler(ChangeHandler<This> handler) {
            handlers.add(handler);
        }
    
        @SuppressWarnings("unchecked")
        protected void reportChange() {
            for (ChangeHandler<This> handler: handlers)
                handler.onChange( (This)this );
        }
    }
    

    Notice the cast (This)this.

    See also Java generics: Use this type as return type?

    0 讨论(0)
  • 2020-12-11 16:38

    It is a really abstract problem. In my opinion the short answer to "how to make this cleaner" is: only use generics where it is needed.

    public class List<T extends List<T>>
    

    What is this trying to express (substituted)? A list which only allows to hold (T extends) other lists which themselves hold Ts (List) which as we know from before are Lists which only allow to hold ... and so on. Kind of circular, I don't see how you would end up with something like that?

    public interface ChangeHandler<SourceType> {
        public void onChange(SourceType source);
    }
    

    Why do you want to use generics here? If you want to have a change handler which can handle several resource types, then you can either create a super class from which all actual sources inherit or you create an interface which is implemented by the sources. Like that you can exactly specify what is exposed by the sources. Alternatively the source can create a source object when notifying instead of passing "this" (then it is more like a message). For example:

    public interface ChangeHandler {
        public void onChange(Source source);
    }
    
    public abstract class Source {
        private List<ChangeHandler> handlers;
        protected int nr;
        public Source(int nr) {
          this.nr = nr;
        }
        public abstract Something getSomething();
        public String toString() {
            return "SRC" + nr;
        }
        ...
        private notify(int index) {
            handlers.get(i).onChange(this);
        }
    }
    
    public class Foo extends Source {
        public Foo(int nr) {
            super(nr);
        }
        public String toString() {
            return super.toString() + "Foo";
        }
        public Something getSomething() {
            return new Something();
        }
    }
    

    You never need to cast... or do you? I'm not sure if I understand the problem.

    0 讨论(0)
提交回复
热议问题