сокращение списка параметров, приводящее к дублированию кода - PullRequest
0 голосов
/ 31 марта 2019

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

depositCash(int fives, int tens, int twenties, int fifties){...}

Я знаю, что плохая практика - иметь функцию со слишком большим количеством параметров, таких как 4. Поэтому я попытался связать эти параметры в новый класс billBundle и передать егов качестве параметра вместо.Но потом я столкнулся с новой проблемой: мне постоянно приходилось писать повторяющийся код, подобный следующему:

Billbundle billBundle = new BillBundle();
billBundle.setFives(fives);
billBundle.setTens(tens);
billBundle.setTwenties(twenties);
billBundle.setFifties(fifties);
depositCash(billBundle);

И если бы я просто передал все счета в пакет, то это было бы именно то, что я пыталсяизбегать в первую очередь.Как мне справиться с этим?Спасибо.

Ответы [ 2 ]

2 голосов
/ 31 марта 2019

BillBundle в качестве объекта параметра - это масштабируемый подход для сокращения списка параметров методов.Как любая реализация шаблона проектирования объекта параметра подразумевает также перемещение по коду, обрабатывающему параметры.Возможность избежать дублирования кода при получении счетов и передачи их таким методам, как depositCash, может быть сочетанием шаблона проектирования посетителя для получения счетов и шаблона проектирования метода шаблона обрабатывать их

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

interface BillEmitter {

    int getFives();

    int getTens();

    int getTwenties();

    int getFifties();

    default void accept(Visitor v) {
        v.visit(this);
    }
}

// add BillEmitter implementations as needed

public class SomeBillEmitter implements BillEmitter {

    private Atm atm;

    public SomeBillEmitter(Atm atm) {
        this.atm = atm;
    }

    public int getFives() {
        int theFivesBill = 0;
        // compute the fives bill with the information from ATM
        return theFivesBill;
    }

    public int getTens() {
        int theTensBill = 0;
        // compute the tens bill with the information from ATM
        return theTensBill;
    }

    public int getTwenties() {
        int theTwentiesBill = 0;
        // compute the twenties bill with the information from ATM
        return theTwentiesBill;
    }

    public int getFifties() {
        int theFiftiesBill = 0;
        // compute the fifties bill with the information from ATM
        return theFiftiesBill;
    }
}

Посетители

interface Visitor {

    default void visit(BillEmitter billEmitter) {

        // template method which gets the bills from the billEmitter
        // and pass them to the bill processor

        Billbundle billBundle = new BillBundle();
        billBundle.setFives(billEmitter.getFives());
        billBundle.setTens(billEmitter.getTens());
        billBundle.setTwenties(billEmitter.getTwenties());
        billBundle.setFifties(billEmitter.getFifties());

        processBills(billBundle);
    }

    void processBills(BillBundle billBundle);
}

// add Visitor implementations as needed

public class DepositCashVisitor implements Visitor {

    public void processBills(BillBundle billBundle) {
        // deposit the cash
        ...
    }
}

Использование

public class Atm {
    // add methods which returns information used to emit bills
}

public class Test {

    public static void main(String[] args) {

        Visitor depositCashVisitor = new DepositCashVisitor();

        Atm atm = new Atm();
        BillEmitter billEmitter = new SomeBillEmitter(atm);
        billEmitter.accept(depositCashVisitor);

        // add more bill emitters and visit them with depositCashVisitor
        // or add more visitors and visit billEmitter with them
    }
}
1 голос
/ 31 марта 2019

Ваша BillBundle идея выглядит хорошо для меня. Вы говорите, что вам приходилось многократно писать код:

Billbundle billBundle = new BillBundle();
billBundle.setFives(fives);
billBundle.setTens(tens);
billBundle.setTwenties(twenties);
billBundle.setFifties(fifties);
depositCash(billBundle);

Но вы действительно или вы просто думаете, что можете?

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

Код, который на самом деле не изменяется и не определяет номер каждой купюры, должен просто передавать пакет купюр. Метод, который регистрирует, сколько счетов каждого вида было внесено? Передайте это BillBundle, которое вы получили от подсчета. Метод, который складывает общую сумму денег? Передайте это BillBundle, которое вы получили от подсчета. и т. д.

Это намного лучше, чем обойти все 4 параметра по двум причинам:

  1. Гораздо меньше возможностей запутаться - каждая функция, которая принимает 4 счета-фактуры и передает их в другое место, имеет шанс передать их в неправильном порядке или в неправильных положениях параметров. Это особенно проблематично, поскольку фактические значения имеют одинаковый тип (т. Е. int), и многие аргументы используют этот тип для совершенно разных вещей.

  2. Гораздо меньше кода на самом деле зависит от видов счетов, которые вы поддерживаете. Допустим, ваша страна переключается на монету в 5 долларов, или вы просто не хотите, чтобы они были в машинах больше ... сколько кода нужно изменить, чтобы избавиться от пятерок? Вам нужно будет изменить код, который считает счета, и все остальные вещи, которые на самом деле заботятся о суммах каждого счета, но вам не нужно менять код, который просто проходит эти счета. Они могут просто обойти оригинал BillBundle и не беспокоиться об этом.

Одно изменение, которое я хотел бы предложить, - сделать ваш BillBundle неизменным. Тогда вам не нужно беспокоиться о том, чтобы кто-нибудь изменил его, когда вы его передаете.

Что-то вроде:

class BillBundle
{
    public final int fives;
    public final int tens;
    public final int twenties;
    public final int fifties;

    public BillBundle(int fives, int tens, int twenties, int fifties)
    {
       this.fives = fives;
       this.tens = tens;
       this.twenties = twenties;
       this.fifties = fifties;
    }
}

Я предупрежу вас, что большинство Java-программистов предпочитают методы getter вместо открытых полей final, но для этого нет веских причин.

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