简体   繁体   中英

Is this the right way to implement Factory Method design pattern

I have to implement a fee structure different for various franchise depending on certain criteria. i make an Abstract Class for FranchiseFeeStructure

    public abstract class FranchiseFeeStructure {
        private BigDecimal registrationFee=1500;
        protected BigDecimal monthlyFee;

    public BigDecimal getMonthlyFees(){  
            return monthlyFee;  
        }

    public BigDecimal  calculateFee{
        //calculate fee here 
        return fee;
        }
}

Now for different structure i make classes which extends FranchiseFeeStructure like

public class ST1 extends FranchiseFeeStructure{
    @Override
     void getMonthlyFee(){
         monthlyFee=890;
     }

}

and ST2, ST3 and so on for various structures. and we have a class to have static factory method.

public class GetFeeStructureFactory {

    public static  FranchiseFeeStructure getFranchiseFeeStructure(String franchiseFeeStructureType){  

         if(franchiseFeeStructureType == null){  
          return null;  
         }  
       if(franchiseFeeStructureType.equalsIgnoreCase("ST1")) {  
              return new ST1();  
            }   
        else if(franchiseFeeStructureType.equalsIgnoreCase("ST2")){  
    /// so on...

    }
}

Now use it as

FranchiseFeeStructure franchiseFeeStructure = GetFeeStructureFactory.getFranchiseFeeStructure("ST1");
        franchiseFeeStructure.getMonthlyFee();
            franchiseFeeStructure.calculateFee();

Is this the right way to implement the method Factory pattern. Please tell me if i am wrong or any suggestion to make it better.

The problem is not so in the factory implementation. It's in the way your abstract class is implemented. It forces every caller to initialize the monthly fee, by calling a (badly named) method getMonthlyFee() . The caller shouldn't have to do that. And your abstract class should rely... on an abstract method to do that:

public abstract class FranchiseFeeStructure {
    private static final BigDecimal REGISTRATION_FEE = new BigDecimal(1500);

    public final BigDecimal calculateFee {
        BigDecimal monthlyFee = getMonthlyFee();
        // TODO compute
        return fee;
    }

    /**
     * Subclasses must implement this method to tell what their monthly fee is
     */
    protected abstract BigDecimal getMonthlyFee();
}

public class ST1 extends FranchiseFeeStructure {
    @Override
    protected BigDecimal getMonthlyFee(){
        return new BigDecimal(890);
    }
}

That way, the caller doesn't need to initialize the monthly fee. All it needs to do is

BigDecimal fee = FeeStructureFactory.getFranchiseFeeStructure("ST1").calculateFee();

Note that if the monthly fee is always a constant value, you don't even need an abstract class and multiple subclasses. All you need is a single class taking the monthly fee as a constructor argument.

Well yeah the idea is the same but you can improve your code. I will suggest an improvement according to me. I will present it with an interface and implementation not with abstract class but the idea is the same.

interface FranchiseFee{
  BigDecimal getMonthlyFee();
  BigDecimal calculateFee():
}

public class CocaColaFee implements FranchiseFee{

   public BigDecimal getMonthlyFee(){
     return new BigDecimal("..");
   }

   public BigDeicaml calculateFee(){
     // do the calculation
   }

}

public class PepsiFee implements FranchiseFee{

   public BigDecimal getMonthlyFee(){
     return new BigDecimal("..");
   }

   public BigDeicaml calculateFee(){
     // do the calculation
   }

}

public FranchiseFeeFactoty {


// this is the easiest way to avoid if/else which makes the code awful. Also to use this you need to have default constructor, because as you can see you need additional code and it get's complicated.

//the other way is to use map but it's just a more convenient if/else approach

   public static FranchiseFee create(Class<? extends FranchiseFee> franchiseFeeType){

     try {
            return franchiseFeeType.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

   }
}

If you need anything else just ask for it :) i will try to help you

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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