资讯专栏INFORMATION COLUMN

使用工厂方法模式实现各种不同分润规则

junbaor / 3288人阅读

摘要:本人邮箱欢迎转载转载请注明网址代码已经全部托管有需要的同学自行下载引言在上一篇文章中使用简单工厂编写不同的分润规则遗留着一个问题那就是如果要新增分润规则则需要修改原来的类也就是代码没有完全解耦因此在这一篇中我将分润规则的设计改为抽象工厂模式

本人邮箱:
欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代码已经全部托管github有需要的同学自行下载

引言

在上一篇文章中使用简单工厂编写不同的分润规则遗留着一个问题,那就是如果要新增分润规则,则需要修改原来的类.也就是代码没有完全解耦.
因此在这一篇中,我将分润规则的设计改为抽象工厂模式来编写.以解决上次遗留的问题.

改写示例 分润规则接口类

该类与上一篇是一样的.

public interface ProfitRole {
    double getProfit(double money);
}
分润规则抽象工厂类
public abstract class ProfitRoleFactory {

    public static ProfitRole createProfitRole(String profitTypeName, String expression){
        ProfitType profitType = ProfitType.getProfitType(profitTypeName);
        Matcher matcher = profitType.getPattern().matcher(expression);
        if (!matcher.matches()){
            throw new RuntimeException("分润表示时不符合" + profitType.getName() + "的规则.");
        }
        return profitType.getFactory().newProfitRole(profitType, matcher, expression);
    }

    protected abstract ProfitRole newProfitRole(ProfitType profitType, Matcher matcher, String expression);


}

该类主要提供一个统一的接口ProfitRoleFactory.createProfitRole创建分润规则实现类
每一个分润规则实现类对应一个分润规则工厂类,由分润规则工厂类来创建出分润规则对象
再由分润规则对象实现具体的分润细节

分润规则类型

上一篇使用到的枚举类型.但是java不支持动态增加枚举成员.所以如果这一篇还是使用枚举类型的话,则在增加新的分润规则时难免需要修改该枚举类型.
因此,这一篇不是枚举类型.

public class ProfitType {
    // 非捕捉匹配正实数
    public static final String number = "(?:(?:[1-9]+d*)|(?:d))(?:.d+)?";
    // 捕捉匹配正实数
    public static final String realNumber = "(" + number + ")";
    // 捕捉匹配百分比
    public static final String rateNumber = realNumber + "%";

    // 分润规则map
    private static final Map profitTypeMap = new HashMap<>();
    static {
        ProfitType.registerProfitRole("FIXED_RATE",
                "^"+ ProfitType.rateNumber +"$",
                new FixedRateRoleFactory(),
                "每笔收益率为0.1%则填写代理商收益0.1%;");

        ProfitType.registerProfitRole("FIXED_INCOME",
                "^" + ProfitType.realNumber + "$",
                new FixedIncomeRoleFactory(),
                "每笔固定收益1元,则填写代理商收益1.00");

        ProfitType.registerProfitRole("FIXED_RATE_AND_FIXED_INCOME",
                "^"+ ProfitType.rateNumber  + "+" + ProfitType.realNumber + "$",
                new FixedRateAndFixedIncomeRoleFactory(),
                "每笔收益率为0.1%加上固定收益1元,则填写代理商收益0.1%+1.00");

        ProfitType.registerProfitRole("FIXED_RATE_AND_UPPER_LIMIT",
                "^"+ ProfitType.realNumber + "~" + ProfitType.rateNumber + "~" + ProfitType.realNumber  + "$",
                new FixedRateAndUpperLimitRoleFactory(),
                "每笔收益率为0.1%,封顶3元,保底1元则填写代理商收益1.00~0.1%~3.00;");

        ProfitType.registerProfitRole("GRADIENT_RATE",
                "^"+ ProfitType.rateNumber+"(<"+ ProfitType.realNumber+"<"+ ProfitType.rateNumber+")+$",
                new GradientRateRoleFactory(),
                "梯度分润 例如 0.1%<10000<0.2%<20000<0.3%<30000<0.5%");
    }
    
    private String name;
    private String expression;
    private String description;
    private ProfitRoleFactory factory;

    public ProfitType(String name, String expression, ProfitRoleFactory factory, String description) {
        this.name = name;
        this.expression = expression;
        this.factory = factory;
        this.description = description;
    }

    public static Pattern getNumberPattern() {
        return Pattern.compile(number);
    }

    public String getName() {
        return name;
    }

    public Pattern getPattern(){
        return Pattern.compile(this.expression);
    }

    /**
     * 注册分润规则类型
     */
    public static void registerProfitRole(String name, String profitRoleExpression,ProfitRoleFactory factory, String description){
        if (profitTypeMap.containsKey(name)){
            throw new RuntimeException("该"+name+"分润规则已经存在");
        }
        profitTypeMap.put(name, new ProfitType(name, profitRoleExpression, factory, description));
    }

    public ProfitRoleFactory getFactory() {
        return factory;
    }

    public String getDescription() {
        return description;
    }

    /**
     * 根据分润规则名字获取分润规则类型
     */
    public static ProfitType getProfitType(String name){
        return profitTypeMap.get(name);
    }

    public static String getProfitTypeInfo(){
        StringBuilder sb = new StringBuilder();
        for (Map.Entry entry : profitTypeMap.entrySet()){
            sb.append(entry.getKey() + " --> " + entry.getValue().getDescription() + "
");
        }
        return sb.toString();
    }
}

ProfitType.profitTypeMap 存放分润类型名称和分润类型的key-value值
ProfitType.registerProfitRole 提供一个注册分润类型的借口
ProfitType static域 默认增加上一篇提到的5种分润规则

分润规则工厂类和分润规则实现类

目前提供五种分润规则:

每笔固定收益1元,则填写代理商收益1.00

每笔收益率为0.1%则填写代理商收益0.1%

每笔收益率为0.1%加上固定收益1元,则填写代理商收益0.1%+1.00

每笔收益率为0.1%,封顶3元,保底1元则填写代理商收益1.00~0.1%~3.00

梯度分润 例如 0.1%<10000<0.2%<20000<0.3%<30000<0.5%

少于10000 按照 0.1% 分润

少于20000 按照 0.2% 分润

少于30000 按照 0.3% 分润

多于30000 按照 0.5% 分润

分别对应于分润规则工厂类 -> 分润规则实现类:

FixedIncomeRoleFactory -> FixedIncomeRole

FixedRateRoleFactory -> FixedRateRole

FixedRateAndFixedIncomeRoleFactory -> FixedRateAndFixedIncomeRole

FixedRateAndUpperLimitRoleFactory -> FixedRateAndUpperLimitRole

GradientRateRoleFactory -> GradientRateRole

实现新的分润规则

如果需要实现新的分润规则,则分别编写一个分润规则工厂类和分润规则实现类,使其实分别继承(/实现)ProfitRoleFactoryProfitRole,然后再调用ProfitType.registerProfitRole注册一下新的分润规则就万事大吉了.不需要修改原有的代码.也就是实现了完全解耦.

测试类
public class TestProfitRole2 {

    private static final List testDate = Arrays.asList(100.0,200.0,300.0,400.0,700.0,
            1000.0,2000.0,3000.0,7000.0,
            10000.0, 20000.0, 30000.0, 70000.0);

    @Test
    public void test(){
        String profitTypeInfo = ProfitType.getProfitTypeInfo();
        System.out.println(profitTypeInfo);

    }
    @Test
    public void testFixedIncome(){
        for (double data : testDate){
            ProfitRole fixedIncome = ProfitRoleFactory.createProfitRole("FIXED_INCOME", "1.00");
            double profit = fixedIncome.getProfit(data);
            Assert.assertEquals(1.00, profit, 0.00001);
        }
    }

    @Test
    public void testFixedRate(){
        for (double data : testDate){
            ProfitRole fixedRate = ProfitRoleFactory.createProfitRole("FIXED_RATE", "0.1%");
            double profit = fixedRate.getProfit(data);
            Assert.assertEquals(data * 0.1 * 0.01, profit, 0.00001);
        }
    }

    @Test
    public void testFixedRateAndFixedIncome(){
        for (double data : testDate){
            ProfitRole profitRole = ProfitRoleFactory.createProfitRole("FIXED_RATE_AND_FIXED_INCOME", "0.63%+3.00");
            double profit = profitRole.getProfit(data);
            Assert.assertEquals(data * 0.63 * 0.01 + 3.0, profit, 0.00001);
        }
    }

    @Test
    public void testFixedRateAndUpperLimit(){
        for (double data : testDate){
            ProfitRole profitRole = ProfitRoleFactory.createProfitRole("FIXED_RATE_AND_UPPER_LIMIT", "1.00~0.1%~3.00");
            double profit = profitRole.getProfit(data);
            double actual = data * 0.1 * 0.01;
            if (actual < 1.0){
                actual = 1.0;
            }
            if (actual > 3.0){
                actual = 3.0;
            }
            Assert.assertEquals(actual, profit, 0.00001);
        }
    }

    @Test
    public void testGradientRate(){
        for (double data : testDate){
            ProfitRole profitRole = ProfitRoleFactory.createProfitRole("GRADIENT_RATE", "0.1%<1000<0.2%<5000<0.3%<15000<0.5%");
            double profit = profitRole.getProfit(data);
            if (data < 1000){
                Assert.assertEquals(data * 0.01 * 0.1, profit, 0.00001);
            }else if (data < 5000){
                Assert.assertEquals(data * 0.01 * 0.2, profit, 0.00001);
            }else if(data < 15000){
                Assert.assertEquals(data * 0.01 * 0.3, profit, 0.00001);
            }else{
                Assert.assertEquals(data * 0.01 * 0.5, profit, 0.00001);
            }
        }
    }
}
打赏

如果觉得我的文章写的还过得去的话,有钱就捧个钱场,没钱给我捧个人场(帮我点赞或推荐一下)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67061.html

相关文章

  • 使用简单工厂编写不同分润规则

    摘要:本人邮箱欢迎转载转载请注明网址代码已经全部托管有需要的同学自行下载引言在工作项目中遇到以下一个问题公司有一款产品遇到给不同代理商代理售卖但是不同的代理商分润的方式各自不同有以下几个中分润方式每笔固定收益元,则填写代理商收益每笔收益率为则填写 本人邮箱: 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kcogithub: https://github...

    Lucky_Boy 评论0 收藏0
  • 理解设计模式

    摘要:适配器模式将一个类的接口转换成客户希望的另外一个接口。代理模式为其他对象提供一种代理以控制对这个对象的访问。如果用来解决排序问题不符合开闭原则,添加策略需要修改代码用策略模式将策略抽象成接口,不同的策略实现该接口。 简单工厂、工厂方法、抽象工厂 简单工厂 通过定义多个factory.produceXXX()方法,或者通过向factory.produce(type)传递type参数来生成...

    saucxs 评论0 收藏0
  • 准备接入个人支付接口?看完这几款支付产品再做决定!

    摘要:支持的付款方式主打银联信用卡等,付款可以及时到账。支持的付款方式主要是微信支付宝和京东支付。支持微信支付宝扫码支付。 最近在开发自己的网站,想要接入一个第三方的支付平台,但是处在创业初期,还没能成立公司,所以没有企业资质,想接入一款安全且性价比高的收款产品。以本人选择困难症再加点小纠结的个性,对现有的一些第三方支付接口做了一个对比,希望能给有相同需要的和正在寻求相关解决方案的朋友提供一...

    SimonMa 评论0 收藏0
  • 准备接入个人支付接口?看完这几款支付产品再做决定!

    摘要:支持的付款方式主打银联信用卡等,付款可以及时到账。支持的付款方式主要是微信支付宝和京东支付。支持微信支付宝扫码支付。 最近在开发自己的网站,想要接入一个第三方的支付平台,但是处在创业初期,还没能成立公司,所以没有企业资质,想接入一款安全且性价比高的收款产品。以本人选择困难症再加点小纠结的个性,对现有的一些第三方支付接口做了一个对比,希望能给有相同需要的和正在寻求相关解决方案的朋友提供一...

    livem 评论0 收藏0

发表评论

0条评论

junbaor

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<