美文网首页昔我室友屌似卿Java学习笔记程序员
如何从代码设计角度应对产品经理的复杂筛选逻辑

如何从代码设计角度应对产品经理的复杂筛选逻辑

作者: mmlmml | 来源:发表于2017-06-11 22:11 被阅读10次

背景

有这样一种需求,要在一个列表的数据中进行筛选.筛选规则和筛选优先级时常改变(不得不吐槽产品同学才华横溢,富有创意).如果不采取合适的方案去应对,而且你的代码功力又不是很强,那很可能每周加班是你的宿命了.

场景

假设现在有一个产品类,属性如下,有类型,有单价,有让利三个字段.

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@ToString
public class Product {
    private String type;
    private String price;
    private String benefit;
}

产品类型有AB两种,产品A的优先级大于B,当产品的优先级一致时,价格低的优先级更高,当价格一致时,让利大的优先级更高.现在给你一个列表的数据,你要筛选出优先级最高的数据,如果有多个,就取第一个.我们看看有几种解决方案.

方案一:硬撸

public class Demo01 {
    public static void main(String[] args) {
        Product p1 = new Product("A", 10, 5);
        Product p2 = new Product("A", 10, 6);
        Product p3 = new Product("B", 10, 6);
        Product p4 = new Product("B", 9, 6);
        Product p5 = new Product("A", 10, 6);
        List<Product> productList = Lists.newArrayList(p1, p2, p3, p4, p5);

        Product resultProduct = new Product("B", Integer.MAX_VALUE, Integer.MAX_VALUE);

        for (Product product : productList) {
            // A 和 B 比较.A更小
            if (product.getType().compareTo(resultProduct.getType()) < 0) {
                resultProduct = product;
                continue;
            }
            if (product.getType().equals(resultProduct.getType())) {
                // 选择价格低的
                if (product.getPrice() < resultProduct.getPrice()) {
                    resultProduct = product;
                    continue;
                }
                if (product.getPrice().intValue() == resultProduct.getPrice().intValue()) {
                    // 选择让利大的
                    if (product.getBenefit() > resultProduct.getBenefit()) {
                        resultProduct = product;
                    }
                }
            }
        }
        System.out.println(resultProduct);
    }
}

在这种仅仅只有三个筛选条件的情况,这种方式的代码已经十分臃肿,而且,如果维护这份代码,在需求频繁更改的情况下是极其容易出错的.更何况生产环境只会更复杂.当然你可以选择把他们抽成一个方法.然后写单元测试.但是后期维护工作依然巨大.

方案二: 使用List的sort方法进行排序

使用List.sort方法.传入Compartor对象,随后取出排序后的第一个元素.代码如下:

public class Demo02 {
    public static void main(String[] args) {
        Product p1 = new Product("A", 10, 5);
        Product p2 = new Product("A", 10, 6);
        Product p3 = new Product("B", 10, 6);
        Product p4 = new Product("B", 9, 6);
        Product p5 = new Product("A", 10, 6);
        List<Product> productList = Lists.newArrayList(p1, p2, p3, p4, p5);
        productList.sort((pro1, pro2) -> {
            if (pro1.getType().compareTo(pro2.getType()) < 0) {
                return -1;
            }
            if (pro1.getType().equals(pro2.getType())) {
                if (pro1.getPrice() < pro2.getPrice()) {
                    return -1;
                }
                if (pro1.getPrice().intValue() == pro2.getPrice().intValue()) {
                    return pro2.getBenefit() - pro1.getBenefit();
                }
                return 1;
            }
            return 1;
        });
        System.out.println(productList.get(0));
    }
}

这种方式本质上和上面的方案一差不多,应对变化的能力差.但也是这种情况下常见的解决方案.

方案三:责任链

上面的两种方案,本质上来说都是面向过程的开发方式.在这个场景下,实际上我们就是在进行一个操作:过滤.所以我们可以给过滤这个动作建模,然后针对各种不同的过滤条件进行实现.通过组装各种过滤实现达到扩展和调整的目标.实现如下:

给过滤动作建模:

public interface IFilter<T> {
    List<T> filter(List<T> data);
}

实现按类型筛选的过滤器:

public class TypeFilter implements IFilter<Product> {

    private Ordering<Product> ordering = new Ordering<Product>() {
        @Override
        public int compare(Product product, Product t1) {
            return product.getType().compareTo(t1.getType());
        }
    };

    @Override
    public List<Product> filter(List<Product> data) {
        if (CollectionUtils.isEmpty(data)) return data;
        if (data.size() == 1) return data;

        List<Product> result = Lists.newArrayList();
        List<Product> sortResult = ordering.sortedCopy(data);

        String type = sortResult.get(0).getType();

        for (Product product : sortResult) {
            if (type.equals(product.getType())) {
                result.add(product);
            } else {
                break;
            }
        }
        return result;
    }
}

按价格筛选的过滤器

public class PriceFilter implements IFilter<Product> {

    private Ordering<Product> ordering = new Ordering<Product>() {
        @Override
        public int compare(Product product, Product t1) {
            return product.getPrice() - t1.getPrice();
        }
    };

    @Override
    public List<Product> filter(List<Product> data) {
        if (CollectionUtils.isEmpty(data)) return data;
        if (data.size() == 1) return data;

        List<Product> result = Lists.newArrayList();
        List<Product> sortResult = ordering.sortedCopy(data);

        int price = sortResult.get(0).getPrice();

        for (Product product : sortResult) {
            if (price == product.getPrice()) {
                result.add(product);
            } else {
                break;
            }
        }
        return result;
    }
}

按让利筛选的过滤器

public class BenefitFilter implements IFilter<Product> {

    private Ordering<Product> ordering = new Ordering<Product>() {
        @Override
        public int compare(Product product, Product t1) {
            return t1.getBenefit() - product.getBenefit();
        }
    };

    @Override
    public List<Product> filter(List<Product> data) {
        if (CollectionUtils.isEmpty(data)) return data;
        if (data.size() == 1) return data;

        List<Product> result = Lists.newArrayList();
        List<Product> sortResult = ordering.sortedCopy(data);

        int benefit = sortResult.get(0).getBenefit();

        for (Product product : sortResult) {
            if (benefit == product.getBenefit()) {
                result.add(product);
            } else {
                break;
            }
        }
        return result;
    }
}

客户端代码

public class Demo03 {

    public static void main(String[] args) {

        Product p1 = new Product("A", 10, 5);
        Product p2 = new Product("A", 10, 6);
        Product p3 = new Product("B", 10, 6);
        Product p4 = new Product("B", 9, 6);
        Product p5 = new Product("A", 10, 6);
        List<Product> productList = Lists.newArrayList(p1, p2, p3, p4, p5);

        List<IFilter<Product>> filterChain = Lists.newArrayList(
                new TypeFilter(), new PriceFilter(), new BenefitFilter()
        );

        for(IFilter<Product> filter : filterChain){
            productList = filter.filter(productList);
        }

        System.out.println(productList.get(0));
    }
}

使用这种方式似乎代码量更多,但是扩展性和维护性上都有了质的提升.

加规则

只需要写一个IFilter的实现类,并在FilterChain上放到一个合适的位置即可.

不加规则,调整权重

只需要修改FilterChain上的位置即可.

还能做的更好吗?

可以针对产品的需求将所有的Filter实现类都实例化,做成配置,接入到公司的配置管理系统.产品在已有规则下的权重调整只需要在配置系统中修改即可,不需要重新修改代码,编译,部署.这样下来,你还需要加班吗?

相关文章

网友评论

    本文标题:如何从代码设计角度应对产品经理的复杂筛选逻辑

    本文链接:https://www.haomeiwen.com/subject/bfdkqxtx.html