设计模式6大原则:
1.开闭原则:对拓展开放,对修改关闭
2.单一职责原则:一个类只复杂一项职责
3.里氏原则:子类可以扩展父类的功能,但不改变父类原有的功能
4.依赖倒置原则:面向接口编程
5.接口隔离原则:设计接口功能尽量细粒度,最小功能单元
6.迪米特法则:降低耦合度(局部变量中,不要引入新的类)
这里对工厂模式做一个学习记录
这里用简单计算器来举例。
很简单,我们需要3个输入:
a1 代表第一个数字
a2 代表第二数字
operator 代表运算符
这三个参数输入后得到一个输出result
1.平时的写法
/** * 这里简化了验证之类的逻辑 * @param a1 第一个数字 * @param a2 第二个数字 * @param operator 运算符 * @return */ public static double calculate(double a1 , double a2 , String operator) { double result=0; switch (operator) { case "+": result=a1+a2; break; case "-": result=a1-a2; break; case "*": result=a1*a2; break; case "/": result=a1/a2; break; //TODO 也许还有别的这些运算符 default: break; } return result; } //本身这样是没问题的而且也是非常简单的方式去实现计算的逻辑 //如果逻辑简单这样写应该也是没问题的。问题是如果该程序非常复杂,这样的代码是很不好维护的。
2.简单工厂模式(Simple Factory)
用一个专业类(工厂类)来负责一种产品对象(计算方法)的创建。
1.我们将计算方法(+ - * / ...)提取出来单独作为一个类
2.再创建一个工厂类来负责每个计算方法的创建。
//计算方法 //将计算方式抽象成一个类 public abstract class CalculationRule { public abstract double getResult(double param1,double param2); } //简单的加法 public class AddRule extends CalculationRule { @Override public double getResult(double param1, double param2) { return param1+param2; } } //简单的减法 public class SubRule extends CalculationRule { @Override public double getResult(double param1, double param2) { return param1-param2; } } //简单工厂模式(Simple Factory) public class CalculationRuleFactory { public static final String OPR_ADD="+"; //加法 public static final String OPR_SUB="-"; //减法 public static CalculationRule getCalculate(String operator) { CalculationRule cal=null; if (OPR_ADD.contentEquals(operator)) { cal=new AddRule(); }else if(OPR_SUB.contentEquals(operator)) { cal=new SubRule(); } return cal; } } //实际调用方式 public class MainEntry { public static void main(String[] args) { CalculationRule addRule=CalculationRuleFactory.getCalculate(CalculationRuleFactory.OPR_ADD);//获得加法算法; System.out.println(addRule.getResult(0.1,0.2)); } }
这种模式对于只有几种产品的管理来说是比较方便的,如果有很多产品(计算方法)的话,这种方式就不合时宜了。
然后我们会发现,简单工厂模式不符合:
1.单一职责原则:一个工厂负责了多个产品的创建
2.开闭原则:每次扩展算法时,需要修改已有代码
3.工厂方法模式(Factory Method)
对于简单工厂模式的问题:
1.将静态工厂打散,每一个算法对应一个算法工厂。
2.当拓展一个算法时候,对应拓展一个算法工厂。
/** * 工厂方法接口 */ public interface CalculationRuleFactoryInterface { CalculationRule getRule(); } /** * 加法工厂 */ public class AddRuleFactory implements CalculationRuleFactoryInterface { @Override public CalculationRule getRule() { return new AddRule(); } } /** * 减法工厂类 */ public class SubRuleFactory implements CalculationRuleFactoryInterface { @Override public CalculationRule getRule() { return new SubRule(); } //调用 public static void main(String[] args) { //创建工厂 CalculationRuleFactoryInterface factory=new SubRuleFactory(); //请求算法并执行 System.out.println(factory.getRule().getResult(0.2, 0.1)); } //另外一种方式 public class MainEntry { //Spring配置注入 private CalculationRuleFactoryInterface calRulefactory; public void fire() { calRulefactory.getRule().getResult(0.2, 0.1); } //这样通过配置的方式想用什么算法就用什么算法 }
我们发现在工厂方法模式中:每一个工厂类只对应一个产品,即工厂和产品是一一对应的。
但是如果说我们需要一个工厂对应多个产品,那就需要用到抽象工厂模式了。
4.抽象工厂模式(Abstract Factory)
为了满足一对多的情况,这里我们假设我们还需要一个能够显示计算过程的产品
//我们添加一个抽象类 /** * 过程展示 */ public abstract class ProcessView { public abstract void showView(double param1,double param2); } //加和减的过程展示都继承这个类 /** * 加法过程展示 */ public class AddProcessView extends ProcessView { @Override public void showView(double param1, double param2) { System.out.println(""+param1+"+"+param2+"="+(param1+param2)); } } /** * 减法过程展示 */ public class SubProcessView extends ProcessView { @Override public void showView(double param1, double param2) { System.out.println(""+param1+"-"+param2+"="+(param1-param2)); } } //我们将ProcessView统一交由CalculationRuleFactoryInterface管理 /** * 工厂方法接口 */ public interface CalculationRuleFactoryInterface { CalculationRule getRule(); ProcessView showProcess();//这个是新加的 } //同时调整对应的工厂 /** * 加法工厂 */ public class AddRuleFactory implements CalculationRuleFactoryInterface { @Override public CalculationRule getRule() { return new AddRule(); } //下面是新加的 @Override public ProcessView showProcess() { return new AddProcessView(); } } /** * 减法工厂类 */ public class SubRuleFactory implements CalculationRuleFactoryInterface { @Override public CalculationRule getRule() { return new SubRule(); } //下面是新加的 @Override public ProcessView showProcess() { return new SubProcessView(); } } //最后尝试调用 public static void main(String[] args) { // 创建工厂 CalculationRuleFactoryInterface factory = new SubRuleFactory(); // 请求算法并执行 System.out.println(factory.getRule().getResult(0.2, 0.1)); // 请求显示过程 factory.showProcess().showView(0.2, 0.1); }
显示: 0.1 0.2-0.1=0.1
这样来看似乎抽象工厂也没有满足单一职责原则和开闭原则
对于单一职责原则:明显抽象工厂不能满足。
对于开闭原则:在抽象工厂中,如果不增加工厂方法接口中的方法,仅添加产品类型,则是满足开闭原则的。反之不满足。
所以抽象工厂要求设计人员在设计之初就能够全面考虑,不会对现有结构出现删减情况,否则后期维护起来会有大麻烦。
题外:说起来工厂模式很多地方都有使用,我记得ifreecharts,Stimulsoft-reports,特别是apache大家族里面用得很多。本人是CURDBOY,工厂模式真的没怎么写过,哎罪过罪过。