Как провести рефакторинг двух классов с очень похожими методами, но используя разные типы - PullRequest
0 голосов
/ 09 ноября 2018

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

Если вы посмотрите на мой код, вы можете заметить, что много дублирования кода, поскольку реализации методов в каждом классе практически одинаковы - они просто используют разные типы объектов (Хотя InvestmentRequests и FundingRequests также реализуют один и тот же интерфейс).

Так, что было бы идеальным подходом для рефакторинга этого кода? Это можно сделать на уровне интерфейса? Я попытался сделать это, объявив объекты в моем интерфейсе так:

RequestsData allRequests = null;
RequestsData fixedRequests = null;
RequestsData trackerRequests = null;

но это не похоже на то, что я пытаюсь сделать, и я не уверен в синтаксисе.

Интерфейс

public interface RequestDataBase<E,T> {

    T getAllRequests();

    T getFixedRequests();

    T getTrackerRequests();

    void add(E newRequest);

    void addAll(List<E> accounts);
}

Класс A

public class FundingRequestData implements RequestDataBase<FundingRequest,FundingRequestData.FundingRequests> {

private static FundingRequests fundingRequests;
private static FundingRequests fixedFundingRequests;
private static FundingRequests trackerFundingRequests;

private static FundingRequestData instance = new FundingRequestData();

public static FundingRequestData getInstance() {
    return instance;
}

private FundingRequestData() {
    fundingRequests = new FundingRequests();
    fixedFundingRequests = new FundingRequests();
    trackerFundingRequests = new FundingRequests();
}

@Override
public FundingRequests getAllRequests() {
    return fundingRequests;
}

@Override
public FundingRequests getFixedRequests() {
    return fixedFundingRequests;
}

@Override
public FundingRequests getTrackerRequests() {
    return trackerFundingRequests;
}

private void listSpecifier(FundingRequest request) {
    if (request.getType().equals("FIXED")) {
        fixedFundingRequests.add(request);
    } else {
        trackerFundingRequests.add(request);
    }
}

@Override
public void add(FundingRequest newRequest) {
    fundingRequests.add(newRequest);
    listSpecifier(newRequest);
}

@Override
public void addAll(List<FundingRequest> accounts) {
    fundingRequests.getRequests().addAll(accounts);
    for (FundingRequest request : accounts) {
        listSpecifier(request);
    }
}

Класс B

public class InvestmentRequestData implements RequestDataBase<InvestmentRequest,InvestmentRequestData.InvestmentRequests> {
    private static InvestmentRequests investmentRequests;
    private static InvestmentRequests fixedInvestmentRequests;
    private static InvestmentRequests trackerInvestmentRequests;

    private static InvestmentRequestData instance = new InvestmentRequestData();

    public static InvestmentRequestData getInstance() { return instance; }

    private InvestmentRequestData() {
        investmentRequests = new InvestmentRequests();
        fixedInvestmentRequests = new InvestmentRequests();
        trackerInvestmentRequests = new InvestmentRequests();
    }

    public void investAll() {
        for (InvestmentRequest request : investmentRequests.getUnfulfilledRequests()) {
            request.investAll();
        }
    }

    public InvestmentRequests getAllRequests() {
        return investmentRequests;
    }

    public InvestmentRequests getFixedRequests() { return fixedInvestmentRequests; }

    public InvestmentRequests getTrackerRequests() {
        return trackerInvestmentRequests;
    }

    private void listSpecifier(InvestmentRequest newRequest) {
        if(newRequest.getType().equals("FIXED")) {
            fixedInvestmentRequests.add(newRequest);
        } else {
            trackerInvestmentRequests.add(newRequest);
        }
    }

    public void add(InvestmentRequest newRequest) {
        investmentRequests.add(newRequest);

        listSpecifier(newRequest);
    }

    public void addAll(List<InvestmentRequest> newRequests) {
        for (InvestmentRequest request : newRequests) {
            listSpecifier(request);
        }
    }

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Если FundingRequest и InvestmentRequest реализуют один и тот же интерфейс (Запрос), то вам следует иметь дело только с Запросами.

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

Если вам нужно относиться к ним по-разному, я предлагаю двухэтапный рефакторинг (запускать юнит-тесты между каждым шагом!)

Сначала используйте if (x instanceof FundingRequest), чтобы выбрать один путь кода или другой. Это позволяет сделать минимальный рефакторинг, который должен работать. Цель этой части - объединить два обсуждаемых вами класса в один класс.

Не останавливайтесь на этом, хотя, после того, как вы все так реорганизовали, теперь вам нужно вставить эти instanceofs в два класса запроса. Возможно, добавьте новый метод в интерфейс, который вызывает реализацию, и поместите один путь этого оператора if () в FundingRequest, а другой - в InvestmentRequest.

Когда вы закончите с этой частью рефакторинга, ваш класс должен ссылаться только на «Запросы», но не FundingRequest или InvestmentRequest.

0 голосов
/ 09 ноября 2018

Вы не сможете рефракторировать универсальные объекты на уровне интерфейса, иначе вы бы рефракторили как FundingRequest (s), так и InvestmentRequest (s) к одному и тому же объекту, что, я думаю, не является вашим намерением.

Я бы преломил объекты в классах А и В. Однако общий дизайн, вероятно, можно улучшить. Что-то вроде того, что InvestmentRequest и FundingRequest реализуют интерфейс Request, поэтому вместо использования обобщенных E и T в интерфейсе RequestDataBase вы можете использовать объекты Request и Requests.

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