Наследование цепочек Java с помощью инъекций Lombok и Guice - PullRequest
0 голосов
/ 28 сентября 2018

РЕДАКТИРОВАТЬ: Этот вопрос действительно должен касаться Lombok и Guice, а не ванильного Java-наследования.

Я пытаюсь реализовать цепочку наследования Java с инъекциями Lombok и Guice, это работаеткак то так:

Класс 1

public abstract class Animal { 
    @NonNull protected String attr1;
    protected abstract void method1();

    void method0() {
        // Some code that uses attr1
    }
}

Класс 2

public abstract class Mammal extends Animal { 
    @NonNull protected String attr2;
    protected abstract void method2();

    @Override 
    void method1() {
        // some logic that uses attr2
        method2();
    }
}

Класс 3

public class Wolf extends Mammal { 
    @Inject @NonNull private String attr1;
    @Inject @NonNull private String attr2;
    @Inject @NonNull private String attr3;

    @Override 
    void method2() {
        // some logic
    }
}

Там, в mainУ меня есть программа, которая вызывает wolf.method1().Проблема здесь в том, что только wolf имеет все необходимые атрибуты (из-за инъекций Guice), тогда как все поля в Animal не определены.Я подозреваю, что я могу сделать это в Vanilla Java, но все будет очень грязно (у меня есть 6 атрибутов в Animal классе и еще 5 в Mammal).Есть ли способ смешать и сопоставить аннотации lombok (@NoArgsConstructor, @AllArgsConstructor и т. Д.), Чтобы это работало?

Спасибо.

Ответы [ 3 ]

0 голосов
/ 28 сентября 2018

Я предлагаю:

  1. использовать только интерфейсы для всей иерархии.
  2. отделить поведения и инкапсулировать их в отдельных классах.
  3. использовать композицию вместо наследования, то есть private SomeBehavior someBehavior;для каждого конкретного животного, которое нуждается в этом.

Это улучшит ваш дизайн и решит проблему.

i.e. 
public interface Mammals {
}

public interface Animal extends Mammals {
}

public interface Dog extends Animal {
}

and 
public class TakeADump {
   public void dump() {
   }
}

public class TakeAPee {
   public void pee() {
   }
}

, а затем

public class Sheperd implements Dog {
    private TakeADump dumpService;

    private TakeApee peeService;
}

И теперь ваша собака может s ... и p ...:)

Также добавить

public class F... {
    public void f...(<Animal> animal) {
        // ... check it's an instance of the same or compatible animal or throw UnsupportedOperationException() if it's incompatible
    }
}

: D

Конечно, имеет смысл создатьабстрактное животное.

т.е.

public class AbstractAnimal {
        private TakeADump dumpService;

        private TakeApee peeService;  

        private F... f...Service;
}

затем

public abstract class AbstractDog extends AbstractAnimal implements Dog {
}

и

public class Sheperd extends AbstractDog {
    public void lookAfterSheep() {
        Sheep sheep = SheepLocator.findNearest();
        // pee on a sheep
        peeService.pee(sheep);
        // dump on a sheep
        dumpService.dump(sheep);
        // f... a sheep
        f...Service.mount(sheep);
    }
}

Таким образом, ваша ошибка заключается в использовании слишком большого количества абстрактного, когда вы можете использовать интерфейсы.

0 голосов
/ 28 сентября 2018

Когда вы реализуете концепцию наследования с помощью какого-либо конструктора аргументов, рекомендуется иметь один конструктор по умолчанию (без аргументов), определенный там.Потому что при создании объекта дочернего класса компилятор внутренне будет вызывать конструктор родительского класса.Например,

class ABC {

 }
 class XYZ implements ABC{

 }
 public class Test{
  XYZ obj= new XYZ() // this will internally call default constructor of XYZ and
  //in that first statement will super()--> this will call default constructor of class ABC
 }

, если каким-либо образом вы реализовали конструктор аргумента в родительском классе, тогда компилятор не будет неявно реализовывать конструктор по умолчанию, нам нужно определить его явно, чтобы сделать вызов супер-конструктора из дочернего конструктора.Или сделайте явный вызов конструктора аргумента из дочернего конструктора.

0 голосов
/ 28 сентября 2018

Ваши абстрактные классы не могут быть напрямую созданы, даже если вы добавите открытые конструкторы, потому что они объявлены абстрактными.Если вы предпочитаете, вы можете сделать конструкторы protected, чтобы указать, что они доступны только для подклассов.

правильно, что абстрактные классы не могут быть действительно созданы, но почему компилятор Java не перехватилэто и перестать жаловаться на отсутствие конструктора?

Любой класс, который вы пишете без явного конструктора, имеет неявный конструктор без аргументов.Любой неявный конструктор без аргументов неявно вызывает конструктор суперкласса без аргументов, даже если этот суперкласс является абстрактным.Поэтому, если какой-то класс в цепочке не имеет конструктора без аргументов (потому что вы явно дали ему другой конструктор), то ваш код не будет компилироваться.

В коде, который вы дали в своем вопросе, естьне являются явными конструкторами, поэтому у каждого класса есть неявный конструктор без аргументов.В вашем реальном коде, вероятно, вы где-то написали конструктор, поэтому неявный конструктор без аргументов не был добавлен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...