简体   繁体   English

有谁知道告诉我这段代码是否可重构? 如果是这样怎么办?

[英]does anyone know tell me if this code is refactorable? And if so how?

    private void fillInvoiceListForName(String name, ArrayList<Invoice> mInvoices) {
    for (SupplierAccount account : listcontracts) {
        if (account.getSupplier() != null)
            if (account.getSupplier().equals(name)) {
                ArrayList<Contract> mContracts = account.getContracts();
                for (Contract contract : mContracts) {
                    mInvoices.addAll(contract.getInvoices());
                }
            }
    }
}

private void fillIncomeListForName(String name, ArrayList<Income> mIncomes) {
    for (SupplierAccount account : listcontracts) {
        if (account.getSupplier() != null)
            if (account.getSupplier().equals(name)) {
                ArrayList<Contract> mContracts = account.getContracts();
                for (Contract contract : mContracts) {
                    mIncomes.addAll(contract.getIncomes());
                }
            }
    }
}


private void fillDocumentListForName(String name, ArrayList<Document> mDocuments) {
    for (SupplierAccount account : listcontracts) {
        if (account.getSupplier() != null)
            if (account.getSupplier().equals(name)) {
                ArrayList<Contract> mContracts = account.getContracts();
                for (Contract contract : mContracts) {
                    mDocuments.addAll(contract.getDocuments());
                }
            }
    }
}

All of your methods have the iteration in common. 您所有的方法都有相同的迭代。 What you want to do is abstract the iteration method while allowing the caller to specify an action to perform on the objects being iterated over. 您想要做的是抽象迭代方法,同时允许调用方指定要对要迭代的对象执行的操作。 Essentially you want to combine an internal iterator (to perform the iteration) with a strategy (to perform the action). 本质上,您希望将内部迭代器(以执行迭代)与策略(以执行动作)结合在一起。

With the Strategy pattern you can define different strategies which all have something in common, and then easily substitute one for the other. 使用策略模式,您可以定义不同的策略,这些策略都有一些共同点,然后可以轻松地用另一种策略替代。 In this case, all of your methods collect information from a list of contracts and adds it to a list, though which information they collect varies. 在这种情况下,您所有的方法都从合同列表中收集信息并将其添加到列表中,尽管它们收集的信息有所不同。

Refactored method 重构方法

private <E> void fillListForName(String name, List<? super E> listToFill, FillStrategy<E> fillStrategy) {
    if (name == null) {
        throw new IllegalArgumentException("name cannot be null");
    }
    for (SupplierAccount account : listContracts) {
        if (name.equals(account.getSupplier())) {
            List<Contract> contracts = account.getContracts();
            for (Contract contract : contracts) {
                fillStrategy.execute(listToFill, contract);
            }
        }
    }
}

The FillStrategy interface and an example implementation FillStrategy接口和示例实现

interface FillStrategy<T> {
    public void execute(List<? super T> listToFill, Contract contract);
}

class InvoiceFillStrategy implements FillStrategy<Invoice> {
    @Override
    public void execute(List<? super Invoice> listToFill, Contract contract) {
        listToFill.addAll(contract.getInvoices());
    }   
}

Calling the refactored method 调用重构方法

List<Invoice> invoices = new ArrayList<Invoice>();
InvoiceFillStrategy invoiceStrategy = new InvoiceFillStrategy();

System.out.println("Invoices for myCorp:");
fillListForName("myCorp", invoices, invoiceStrategy);
for (Invoice i : invoices) {
    System.out.println(i);
}

System.out.println("\nInvoices for otherCorp:");
invoices.clear();
fillListForName("otherCorp", invoices, invoiceStrategy);
for (Invoice i : invoices) {
    System.out.println(i);
}

Why? 为什么?

The benefit of this approach is that you can create additional "strategies" without necessarily modifying any of the other classes involved. 这种方法的好处是您可以创建其他“策略”,而不必修改任何其他涉及的类。 For example, you could create one that collects all invoices for sums over a given threshold: 例如,您可以创建一个收集超过给定阈值总和的所有发票的发票:

class ExpensiveInvoiceFillStrategy implements FillStrategy<Invoice> {

    private int minimumAmount;

    public ExpensiveInvoiceFillStrategy(int minimumAmount) {
        this.minimumAmount = minimumAmount;
    }

    @Override
    public void execute(List<? super Invoice> listToFill, Contract contract) {
        for (Invoice invoice : contract.getInvoices()) {
            if (invoice.getAmount() >= minimumAmount) {
                listToFill.add(invoice);
            }
        }
    }
}

Just implementing this class and then calling fillListForName with an instance of it is enough - no change to fillListForName or Contract is necessary! 只需实现此类,然后使用其实例调用fillListForName就足够了-无需更改fillListForNameContract

There are other ways to implement the iterator method and the strategies - some would even be considered "more pure" or "better" that what I've done here. 还有其他实现迭代器方法和策略的方法-甚至被认为比我在这里所做的“更纯粹”或“更好”。 I chose this approach because it kept the code similar to what you had, and because we're trying to solve a specific problem, not implement general support for internal iterators in Java (smarter guys are already working on that). 我之所以选择这种方法,是因为它使代码与您的代码保持相似,并且因为我们正在尝试解决特定的问题,而不是在Java中实现对内部迭代器的常规支持(更聪明的人已经在为此工作)。 Just be aware that it's not "perfect" :) 请注意,它不是“完美的” :)

Consider using Guava , it has powerful utilities for manipulating collections. 考虑使用Guava ,它具有用于操作集合的强大实用程序。 For example, you could use FluentIterable in conjunction with Predicate s and Function s, to extract common logic, and use them to transform and filter your collections. 例如,可以将FluentIterablePredicateFunction结合使用,以提取通用逻辑,并使用它们来转换和过滤集合。

Below I have extracted common elements into the filterAndTransform method which allows you to pass in a Function so you can collect what you like from the Contract object: 下面,我将常见元素提取到filterAndTransform方法中,该方法允许您传递Function以便可以从Contract对象中收集所需的内容:

private <T> List<T> filterAndTransform(String name, Function<Contract, Iterable<T>> function) {
    return FluentIterable.from(listcontracts)
        .filter(new HasSupplierPredicate())
        .filter(new SupplierNameMatchesPredicate(name))
        .transformAndConcat(new Function<SupplierAccount, Iterable<Contract>>() {
            @Override public Iterable<Contract> apply(final SupplierAccount account) {
                return account.getContracts();
            }
        })
        .transformAndConcat(function)
        .toList();
}

private void fillInvoiceListForName(String name, ArrayList<Invoice> mInvoices) {
    final Iterable<Invoice> invoices = filter(name, 
        new Function<Contract, Iterable<Invoice>>() {
            @Override public Iterable<Invoice> apply(final Contract contract) {
                return contract.getInvoices();
            }
    });
    mInvoices.addAll(invoices);
}

private void fillIncomeListForName(String name, ArrayList<Income> mIncomes) {
    final Iterable<Income> incomes = filter(name, 
        new Function<Contract, Iterable<Income>>() {
            @Override public Iterable<Income> apply(final Contract contract) {
                return contract.getIncomes();
            }
    });
    mIncomes.addAll(incomes);
}

// etc...

Define an enum, and pass it as a parameter to a method: 定义一个枚举,并将其作为参数传递给方法:

public enum ContractValue {
    INVOICE, INCOME, DOCUMENT;
}

private void fillIncomeListForName(String name, ArrayList<Income> mIncomes, ContractValue contractValue) {
for (SupplierAccount account : listcontracts) {
    if (account.getSupplier() != null)
        if (account.getSupplier().equals(name)) {
            ArrayList<Contract> mContracts = account.getContracts();
            for (Contract contract : mContracts) {
                if (contractValue == ContractValue.INCOME) {
                     mIncomes.addAll(contract.getIncomes()); 
                } else if (contractValue == ContractValue.INVOICE) {
                     mInvoices.addAll(contract.getInvoices());
                } else if (contractValue == ContractValue.DOCUMENT) {
                     mDocuments.addAll(contract.getDocuments());
                }
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM