设计模式-第6章(工厂模式)

文章介绍了简单工厂模式和工厂方法模式在实现上的区别,强调了工厂方法如何遵循开放-封闭原则,通过代码示例展示了如何在不同场景下使用这两种模式,包括在商场收银程序中的应用,同时提到了结合策略和装饰模式的使用,以提高代码的灵活性和可扩展性。
摘要由CSDN通过智能技术生成

简单工厂实现

在这里插入图片描述
在简单工厂类中,通过不同的运算符,创建具体的运算类。

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://300100
                fs = new CashRebateReturnFactory(1,300d,100d);
                break;
            case 5://先打8,再满300100
                fs = new CashRebateReturnFactory(0.8d,300d,100d);
                break;
            case 6://先满20050,再打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("**********************************************");
	}
}

工厂方法模式总结

工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持封装对象创建过程的优点。
工厂方法模式是简单工厂模式的进一步抽象和推广。是对获取对象过程的进一步抽象。

工厂方法模式的好处

  • 对于复杂的参数的构造对象,可以很好地对外层屏蔽代码的复杂性。
  • 很好的解耦能力,针对接口编程,屏蔽了细节。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值