工厂模式
- 简单工厂实现
- 工厂模式实现
- 简单工厂 VS 工厂方法
- 商场收银程序再再升级(简单工厂+策略+装饰+工厂方法)
- 工厂方法模式总结
简单工厂实现
在简单工厂类中,通过不同的运算符,创建具体的运算类。
public class OperationFactory {
public static Operation createOperate(String operate){
Operation oper = null;
switch (operate) {
case "+":
oper = new Add();
break;
case "-":
oper = new Sub();
break;
case "*":
oper = new Mul();
break;
case "/":
oper = new Div();
break;
}
return oper;
}
}
工厂模式实现
工厂类
// 工厂接口
public interface IFactory {
public Operation createOperation();
}
//减法工厂
public class SubFactory implements IFactory {
public Operation createOperation(){
return new Sub();
}
}
//加法工厂
public class AddFactory implements IFactory {
public Operation createOperation(){
return new Add();
}
}
//除法工厂
public class DivFactory implements IFactory {
public Operation createOperation(){
return new Div();
}
}
//乘法工厂
public class MulFactory implements IFactory {
public Operation createOperation(){
return new Mul();
}
}
运算类
// 抽象运算类
public abstract class Operation {
public double getResult(double numberA, double numberB){
return 0d;
}
}
// 减法运算类
public class Sub extends Operation {
public double getResult(double numberA, double numberB){
return numberA - numberB;
}
}
// 加法运算类
public class Add extends Operation {
public double getResult(double numberA, double numberB){
return numberA + numberB;
}
}
// 除法运算类
public class Div extends Operation {
public double getResult(double numberA, double numberB){
if (numberB == 0){
System.out.println("除数不能为0");
throw new ArithmeticException();
}
return numberA / numberB;
}
}
// 乘法运算类
public class Mul extends Operation {
public double getResult(double numberA, double numberB){
return numberA * numberB;
}
}
运算工厂
public class OperationFactory {
public static Operation createOperate(String operate){
Operation oper = null;
IFactory factory = null;
switch (operate) {
case "+":
// 隐藏了具体运算类的创建过程
factory = new AddFactory();
break;
case "-":
factory = new SubFactory();
break;
case "*":
factory = new MulFactory();
break;
case "/":
factory = new DivFactory();
break;
}
oper = factory.createOperation();
return oper;
}
}
客户端
public class Test {
public static void main(String[] args){
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A:");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请选择运算符号(+、-、*、/):");
String strOperate = sc.nextLine();
System.out.println("请输入数字B:");
double numberB = Double.parseDouble(sc.nextLine());
Operation oper = OperationFactory.createOperate(strOperate);
double result = oper.getResult(numberA,numberB);
System.out.println("结果是:"+result);
}
catch(Exception e){
System.out.println("您的输入有错:"+e.toString());
}
System.out.println();
System.out.println("**********************************************");
}
}
简单工厂 VS 工厂方法
简单工厂模式的最大优点在于工厂类中包含必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
在简单工厂中,由于每次增加运算类,都需要在工厂类中增加Case分支条件。这对于工厂类来说,不是一个好办法,频繁的进行修改,违反了开放-封闭原则。
尽量将长的代码分派切割成小段,再将每一小段封装起来,减少每段代码之间的耦合,这样风险就分散了,需要修改或扩展的难度就降低了。
可以将加减乘除基础的运算类,由一个基础运算工厂进行创建,增加的指数,对数运算类,再增加一个高级运算工厂类进行创建。就不会影响基础运算类的部分。
// 抽象工厂接口
public interface IFactory {
public Operation createOperation(String operType);
}
//基础运算工厂
public class FactoryBasic implements IFactory {
public Operation createOperation(String operType){
Operation oper = null;
switch (operType) {
case "+":
oper = new Add();
break;
case "-":
oper = new Sub();
break;
case "*":
oper = new Mul();
break;
case "/":
oper = new Div();
break;
}
return oper;
}
}
//高级运算工厂
public class FactoryAdvanced implements IFactory {
public Operation createOperation(String operType){
Operation oper = null;
switch (operType) {
case "pow":
oper = new Pow();//指数运算类实例
break;
case "log":
oper = new Log();//对数运算类实例
break;
//此处可扩展其他高级运算类的实例化,但修改
//当前工厂类不会影响到基础运算工厂类
}
return oper;
}
}
运算工厂类
public class OperationFactory {
public static Operation createOperate(String operate){
Operation oper = null;
IFactory factory = null;
switch (operate) {
case "+":
case "-":
case "*":
case "/":
//基础运算工厂实例
factory=new FactoryBasic();
break;
case "pow":
case "log":
//高级运算工厂实例
factory=new FactoryAdvanced();
break;
}
//利用多态返回实际的运算类实例
oper = factory.createOperation(operate);
return oper;
}
}
客户端
public class Test {
public static void main(String[] args){
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
try {
Scanner sc = new Scanner(System.in);
System.out.println("请输入数字A:");
double numberA = Double.parseDouble(sc.nextLine());
System.out.println("请选择运算符号(+、-、*、/):");
String strOperate = sc.nextLine();
System.out.println("请输入数字B:");
double numberB = Double.parseDouble(sc.nextLine());
Operation oper = OperationFactory.createOperate(strOperate);
double result = oper.getResult(numberA,numberB);
System.out.println("结果是:"+result);
}
catch(Exception e){
System.out.println("您的输入有错:"+e.toString());
}
System.out.println();
System.out.println("**********************************************");
}
}
在新的 OperationFactory类已经不存在实例化运算子类的代码,在这个代码里,全是接口和具体工厂类。将实例化的过程放到了子类工厂中。这就是针对接口编程,不要对实现编程。
工厂方法模式(Factory Method),定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂方法模式结构图
商场收银程序再再升级(简单工厂+策略+装饰+工厂方法)
在上一版代码中,通过简单工厂,对于不同的条件,生成具体的收费策略类。可以使用工厂方法模式替代简单工厂。
对于不同的收费策略,可以分为两类,先打折后满减和先满减后打折。
// 工厂接口
public interface IFactory {
public ISale createSalesModel(); //创建销售模式
}
//先打折再满减类
public class CashRebateReturnFactory implements IFactory {
private double moneyRebate = 1d;
private double moneyCondition = 0d;
private double moneyReturn = 0d;
public CashRebateReturnFactory(double moneyRebate,double moneyCondition,double moneyReturn){
this.moneyRebate = moneyRebate;
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
//先打x折,再满m返n
public ISale createSalesModel(){
CashNormal cn = new CashNormal();
CashReturn cr1 = new CashReturn(this.moneyCondition,this.moneyReturn);
CashRebate cr2 = new CashRebate(this.moneyRebate);
cr1.decorate(cn); //用满m返n算法包装基本的原价算法
cr2.decorate(cr1); //打x折算法装饰满m返n算法
return cr2; //将包装好的算法组合返回
}
}
//先满减再打折类
public class CashReturnRebateFactory implements IFactory {
private double moneyRebate = 1d;
private double moneyCondition = 0d;
private double moneyReturn = 0d;
public CashReturnRebateFactory(double moneyRebate,double moneyCondition,double moneyReturn){
this.moneyRebate = moneyRebate;
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
//先满m返n,再打x折
public ISale createSalesModel(){
CashNormal cn2 = new CashNormal();
CashRebate cr3 = new CashRebate(this.moneyRebate);
CashReturn cr4 = new CashReturn(this.moneyCondition,this.moneyReturn);
cr3.decorate(cn2); //用打x折算法包装基本的原价算法
cr4.decorate(cr3); //满m返n算法装饰打x折算法
return cr4; //将包装好的算法组合返回
}
}
// 收费接口
public interface ISale {
public double acceptCash(double price,int num);
}
public class CashNormal implements ISale {
//正常收费,原价返回
public double acceptCash(double price,int num){
return price * num;
}
}
public class CashSuper implements ISale {
protected ISale component;
//装饰对象
public void decorate(ISale component) {
this.component = component;
}
public double acceptCash(double price,int num){
if (this.component != null){
//若装饰对象存在,则执行装饰的算法运算
return this.component.acceptCash(price,num);
}
else
return 0d;
}
}
public class CashRebate extends CashSuper {
private double moneyRebate = 1d;
//打折收费。初始化时必需输入折扣率。八折就输入0.8
public CashRebate(double moneyRebate){
this.moneyRebate = moneyRebate;
}
//计算收费时需要在原价基础上乘以折扣率
public double acceptCash(double price,int num){
double result = price * num * this.moneyRebate;
return super.acceptCash(result,1);
}
}
public class CashReturn extends CashSuper {
private double moneyCondition = 0d; //返利条件
private double moneyReturn = 0d; //返利值
//返利收费。初始化时需要输入返利条件和返利值。
//比如“满300返100”,就是moneyCondition=300,moneyReturn=100
public CashReturn(double moneyCondition,double moneyReturn){
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
//计算收费时,当达到返利条件,就原价减去返利值
public double acceptCash(double price,int num){
double result = price * num;
if (moneyCondition>0 && result >= moneyCondition)
result = result - Math.floor(result / moneyCondition) * moneyReturn;
return super.acceptCash(result,1);
}
}
在 CashContext 中,使用具体的工厂来得到不同的收费策略类。
public class CashContext {
private ISale cs; //声明一个ISale接口对象
//通过构造方法,传入具体的收费策略
public CashContext(int cashType){
IFactory fs=null;
switch(cashType) {
case 1://原价
fs = new CashRebateReturnFactory(1d,0d,0d);
break;
case 2://打8折
fs = new CashRebateReturnFactory(0.8d,0d,0d);
break;
case 3://打7折
fs = new CashRebateReturnFactory(0.7d,0d,0d);
break;
case 4://满300返100
fs = new CashRebateReturnFactory(1,300d,100d);
break;
case 5://先打8折,再满300返100
fs = new CashRebateReturnFactory(0.8d,300d,100d);
break;
case 6://先满200返50,再打7折
fs = new CashReturnRebateFactory(0.7d,200d,50d);
break;
}
this.cs = fs.createSalesModel();
}
public double getResult(double price,int num){
//根据收费策略的不同,获得计算结果
return this.cs.acceptCash(price,num);
}
}
客户端
public class Test {
public static void main(String[] args){
System.out.println("**********************************************");
System.out.println("《大话设计模式》代码样例");
System.out.println();
int discount = 0; //商品折扣模式
double price = 0d; //商品单价
int num = 0; //商品购买数量
double totalPrices = 0d;//当前商品合计费用
double total = 0d; //总计所有商品费用
Scanner sc = new Scanner(System.in);
do {
System.out.println("商品折扣模式如下:");
System.out.println("1.正常收费");
System.out.println("2.打八折");
System.out.println("3.打七折");
System.out.println("4.满300送100");
System.out.println("5.先打8折,再满300送100");
System.out.println("6.先满200送50,再打7折");
System.out.println("请输入商品折扣模式:");
discount = Integer.parseInt(sc.nextLine());
System.out.println("请输入商品单价:");
price = Double.parseDouble(sc.nextLine());
System.out.println("请输入商品数量:");
num = Integer.parseInt(sc.nextLine());
System.out.println();
if (price>0 && num>0){
//根据用户输入,将对应的策略对象作为参数传入CashContext对象中
CashContext cc = new CashContext(discount);
//通过Context的getResult方法的调用,可以得到收取费用的结果
//让具体算法与客户进行了隔离
totalPrices = cc.getResult(price,num);
total = total + totalPrices;
System.out.println();
System.out.println("单价:"+ price + "元 数量:"+ num +" 合计:"+ totalPrices +"元");
System.out.println();
System.out.println("总计:"+ total+"元");
System.out.println();
}
} while(price>0 && num>0);
System.out.println();
System.out.println("**********************************************");
}
}
工厂方法模式总结
工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持封装对象创建过程的优点。
工厂方法模式是简单工厂模式的进一步抽象和推广。是对获取对象过程的进一步抽象。
工厂方法模式的好处
- 对于复杂的参数的构造对象,可以很好地对外层屏蔽代码的复杂性。
- 很好的解耦能力,针对接口编程,屏蔽了细节。