как реализовать функциональный интерфейс с различным первым параметром в каждом подменю - PullRequest
0 голосов
/ 06 октября 2019

Действительно трудно суммировать проблему, но я постараюсь изо всех сил и надеюсь, что вы получите ее. У меня есть enum, который реализует функциональный интерфейс (Выполнение), где единственный метод в Выполнении - это выполнение, которое принимает два параметра

1: AbstractRepository: интерфейс spring-jpa

2: String

Дело в том, что с каждым вложенным перечислением мне нужно реализовать метод execute, но вместо того, чтобы заставить его принимать AbstractRepository, я хочу сделать этопринять интерфейс, который расширяет AbstractRepository.

это перечисление с функциональным интерфейсом.

package com.deepTech.Familytree.enums;

import com.deepTech.Familytree.domain.ImageBox;
import com.deepTech.Familytree.domain.Person;
import com.deepTech.Familytree.exception.PersonException;
import com.deepTech.Familytree.repository.AbstractRepository;

import java.util.Optional;

import static com.deepTech.Familytree.config.AuthDataConfig.getUser;
import static com.deepTech.Familytree.exception.PersonException.ExceptionType.PERSON_NOT_FOUND;


public enum FileManagementEnumExecution implements Execution {


    UPLOAD_PERSON_FILE() {
        @Override
               // rather than AbstractRepository I want to make it accepts a repository that extends an AbstractRepository
        public void execute(AbstractRepository repository, String filename) {
            Optional<Person> person1 = (Optional<Person>) repository
                    .finByTEm(getUser().getEmail());

            person1.map(person -> person.copyByImage(new ImageBox(filename)));


            repository.save(person1.orElseThrow(() -> new PersonException(PERSON_NOT_FOUND)));
        }
    },

    DELETE_PERSON_FILE() {
        @Override
        public void execute(AbstractRepository repository, String filename) {
            Optional<Person> person1 = (Optional<Person>) repository
                    .finByTEm(getUser().getEmail());

            repository.save(person1
                    .map(Person::withoutImage)
                    .orElseThrow(() -> new PersonException(PERSON_NOT_FOUND)));

        }
    },
    UPLOAD_VIP_PERSON_FILE() {
        @Override
        public void execute(AbstractRepository repository, String filename) {

        }
    },

    DELETE_VIP_PERSON_FILE() {
        @Override
        public void execute(AbstractRepository repository, String filename) {


        }
    },
    UPLOAD_NEWS_FILE() {
        @Override
        public void execute(AbstractRepository repository, String filename) {

        }
    },

    DELETE_NEWS_FILE() {
        @Override
        public void execute(AbstractRepository repository, String filename) {


        }
    };

}

@FunctionalInterface
interface Execution {
    void execute(AbstractRepository repository, String filename);
}

@Service
@RequiredArgsConstructor
public class PersonServiceImpl implements PersonInterface {
...
 /* somecode */
...
        @Override
    public UploadFileResponse uploadPersonFile(Long id, MultipartFile file) {
        return fileManagementService.uploadFile(file, id, UPLOAD_PERSON_FILE, personRepository);

    }
...
 /* somecode */
...
}

и здесь класс FileManagementService

@Service
@RequiredArgsConstructor
public class FileManagementService {
...
 /* somecode */
...
    public UploadFileResponse uploadFile(MultipartFile file, Long id, SsssEnum ssssEnum, AbstractRepository neo4jRepository) {
        String fileName = fileStorageService.storeFile(file);

        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/downloadFile/")
                .path(fileName)
                .toUriString();

        FileManagementEnumExecution.execute(neo4jRepository, fileName);

        return new UploadFileResponse(fileName, fileDownloadUri,
                file.getContentType(), file.getSize());
    }
...
 /* somecode */
...
}

может кто-нибудь помочь, пожалуйста

1 Ответ

1 голос
/ 10 октября 2019

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

Чтобы реализации могли указывать типы некоторых параметров и методов, вы должны добавить соответствующие параметры типа в свой интерфейс. Вот как вы можете сделать это в вашем конкретном случае:

@FunctionalInterface
public interface Execution<T extends AbstractRepository> {
    void execute(T repository, String fileName);
}

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

public enum FileManagementExecution implements Execution<ConcreteReprisitory> {
    UPLOAD_PERSON_FILE() {
        @Override
        public void execute(ConcreteReprisitory repository, String fileName) {
            //TODO
        }
    },
    DELETE_PERSON_FILE() {
        @Override
        public void execute(ConcreteReprisitory repository, String fileName) {
            //TODO
        }
    }
    // other enum constants
}

Если FileManagementExecution s принимает разные типы репозитория, вы должны добавить параметр типа вFileManagementExecution также. К сожалению, Java не поддерживает общие перечисления , поэтому в этом случае вам нужно использовать обычный класс:

public abstract class FileManagementExecution<T extends AbstractRepository> implements Execution<T> {
    private FileManagementExecution() {}

    public static final FileManagementExecution<ConcreteReprisitory1> UPLOAD_PERSON_FILE =
            new FileManagementExecution<ConcreteReprisitory1>() {
                @Override
                public void execute(ConcreteReprisitory1 repository, String fileName) {
                    //TODO
                }
            };
    public static final FileManagementExecution<ConcreteReprisitory2> DELETE_PERSON_FILE =
            new FileManagementExecution<ConcreteReprisitory2>() {
                @Override
                public void execute(ConcreteReprisitory2 repository, String fileName) {
                    //TODO
                }
            };
    // other constants
}

Чтобы сделать код немного чище, вы можете заменить abstract class с interface 1 :

public interface FileManagementExecution<T extends AbstractRepository> extends Execution<T> {
    FileManagementExecution<ConcreteReprisitory1> UPLOAD_PERSON_FILE = 
            ((repository, fileName) -> TODO());
    FileManagementExecution<ConcreteReprisitory2> DELETE_PERSON_FILE = 
            ((repository, fileName) -> TODO());
    // other constants
}

1 Если вы сделаете это, вы не сможете запретить реализацию этого интерфейса.

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