Implementing various profit sharing rules using abstract factory pattern

My mailbox: <kco1989@qq.com>.
Welcome to reprint. Please indicate the website for reprinting. http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
The code is fully hosted github Students in need download it by themselves

Introduction

In the last article Write different profit sharing rules using simple factories One problem that remains is that if you want to add new profit-sharing rules, you need to modify the original class. That is, the code is not completely decoupled.
Therefore, in this article, I will change the design of profit sharing rules to abstract factory model to solve the problems left over from the last time.

Rewrite examples

Distribution Rule Interface Class

This category is the same as the previous one.

public interface ProfitRole {
    double getProfit(double money);
}

Profit sharing rule abstract factory class

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("Incompatibility in the expression of profit sharing" + profitType.getName() + "Rules.");
        }
        return profitType.getFactory().newProfitRole(profitType, matcher, expression);
    }

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


}

This class mainly provides a unified interface ProfitRoleFactory.createProfitRole to create a profit sharing rule implementation class.
Each implementation class of profit sharing rules corresponds to a factory class of profit sharing rules. The factory class of profit sharing rules creates the object of profit sharing rules.
Then the specific details of profit distribution are realized by the object of profit distribution rules.

Rule Type of Profit Distribution

The enumeration type used in the previous article. However, java does not support dynamically increasing enumeration members. So if this article still uses enumeration type, it will inevitably need to modify the enumeration type when adding new profit rules.
Therefore, this article is not an enumeration type.

public class ProfitType {
    // Uncaptured Matched Positive Real Number
    public static final String number = "(?:(?:[1-9]+\\d*)|(?:\\d))(?:\\.\\d+)?";
    // Capturing Matched Positive Real Numbers
    public static final String realNumber = "(" + number + ")";
    // Capture matching percentage
    public static final String rateNumber = realNumber + "%";

    // Rule map of profit distribution
    private static final Map<String, ProfitType> profitTypeMap = new HashMap<>();
    static {
        ProfitType.registerProfitRole("FIXED_RATE",
                "^"+ ProfitType.rateNumber +"$",
                new FixedRateRoleFactory(),
                "Each return is 0..1%Then fill in the proxy income 0.1%;");

        ProfitType.registerProfitRole("FIXED_INCOME",
                "^" + ProfitType.realNumber + "$",
                new FixedIncomeRoleFactory(),
                "For each fixed income of $1, fill in the agent income of $1.00");

        ProfitType.registerProfitRole("FIXED_RATE_AND_FIXED_INCOME",
                "^"+ ProfitType.rateNumber  + "\\+" + ProfitType.realNumber + "$",
                new FixedRateAndFixedIncomeRoleFactory(),
                "Each return is 0..1%Add a fixed income of 1 yuan, then fill in the agent's income of 0..1%+1.00");

        ProfitType.registerProfitRole("FIXED_RATE_AND_UPPER_LIMIT",
                "^"+ ProfitType.realNumber + "~" + ProfitType.rateNumber + "~" + ProfitType.realNumber  + "$",
                new FixedRateAndUpperLimitRoleFactory(),
                "Each return is 0..1%,Top 3 yuan, bottom 1 yuan, then fill in the agent's income 1.00~0.1%~3.00;");

        ProfitType.registerProfitRole("GRADIENT_RATE",
                "^"+ ProfitType.rateNumber+"(<"+ ProfitType.realNumber+"<"+ ProfitType.rateNumber+")+$",
                new GradientRateRoleFactory(),
                "Gradient fractionation, e.g. 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);
    }

    /**
     * Types of Rules for Registered Profit Distribution
     */
    public static void registerProfitRole(String name, String profitRoleExpression,ProfitRoleFactory factory, String description){
        if (profitTypeMap.containsKey(name)){
            throw new RuntimeException("this"+name+"The profit-sharing rule already exists.");
        }
        profitTypeMap.put(name, new ProfitType(name, profitRoleExpression, factory, description));
    }

    public ProfitRoleFactory getFactory() {
        return factory;
    }

    public String getDescription() {
        return description;
    }

    /**
     * Get the type of profit distribution rule according to the name of the profit distribution rule
     */
    public static ProfitType getProfitType(String name){
        return profitTypeMap.get(name);
    }

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

ProfitType.profitTypeMap stores the key-value values of the profit type name and the profit type.
ProfitType.registerProfitRole provides an excuse for registering a profit-sharing type.
By default, the ProfitType static domain adds the five profit-sharing rules mentioned in the previous article.

Distribution Rule Factory Class and Distribution Rule Implementation Class

Five profit-sharing rules are currently available:

  1. For each fixed income of 1 yuan, the agent's income is 1.00

  2. For each return of 0.1%, fill in the agent's return of 0.1%.

  3. If the rate of return is 0.1% and the fixed income is 1 yuan, the agent's income is 0.1%+1.00.

  4. The rate of return per transaction is 0.1%, the top is 3 yuan, and the bottom is 1 yuan, then the agent's income is 1.00-0.1%-3.00.

  5. Gradient fraction such as 0.1% < 10 000 < 0.2% < 20 000 < 0.3% < 30 000 < 0.5%.

    • Less than 10,000 at 0.1% profit

    • Less than 2000 according to 0.2% profit

    • Less than 30,000 according to 0.3% profit

    • More than 30,000 according to 0.5% profit

    Corresponding to the factories class of profit sharing rules - > the realization class of profit sharing rules respectively:

  6. FixedIncomeRoleFactory -> FixedIncomeRole

  • FixedRateRoleFactory -> FixedRateRole

  • FixedRateAndFixedIncomeRoleFactory -> FixedRateAndFixedIncomeRole

  • FixedRateAndUpperLimitRoleFactory -> FixedRateAndUpperLimitRole

  • GradientRateRoleFactory -> GradientRateRole

  • Realizing New Rules of Profit Distribution

    If you need to implement a new profit sharing rule, write a profit sharing rule factory class and a profit sharing rule implementation class to inherit (/implement) ProfitRoleFactory and ProfitRole respectively, and then call ProfitType. RegiserProfitRole to register the new profit sharing rule. There is no need to modify the original code. Complete decoupling is realized.

    Test class

    public class TestProfitRole2 {
    
        private static final List<Double> 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);
                }
            }
        }
    }

    Keywords: Java less github

    Added by theslinky on Sun, 07 Jul 2019 23:49:45 +0300