• 设计模式-工厂方法模式


    概述

    工厂方法模式的作用是负责实例化同一个接口的多个类。工厂方法模式的意义是定义一个创建产品对象的工厂类,由该工厂统一创建继承了同一个接口的多个产品对象。

    根据工厂类和工厂方法的不同形式,可以用来表示不同的创建策略。根据决策策略的不同,工厂方法模式可以分为3个子类型。

    • 工厂方法模式(FactoryMethod):最基本的工厂模式
    • 多个工厂方法模式:对工厂方法模式的扩展。
    • 简单工厂模式(Simple Factory):一种特殊的工厂模式,其工厂方法是静态的,因此又称为静态工厂方法模式(Static Factory Method)。

    一、工厂方法模式

    工厂方法模式提供了一个工厂方法类 Farm1,并提供了一个工厂方法函数produce(),该接口负责创建所有的Animal产品对象,其模型如下图所示。
    在这里插入图片描述
    工厂类 Farm1.java 的函数 produce()提供了一个type 参数,根据该参数的值来创建不同的产品对象。

    • type ==“pig”:创建 Pig 对象。
    • type ==“chicke”:创建 Chicken 对象
    • type ==“cattle”:创建 Cattle 对象。
    • type ==“sheep”:创建 Sheep 对象。

    该工厂类的代码如程序:

    package creation.factorymethod;
    /**
    * @author Minggg
    * 工厂方法模式
    */
    public class Farm1 {
    	public Animal produce(String type){
    		if (type == "pig"){
    			return new Pig();
    		} else if (type == "chicken") {
    			return new Chicken();
    		} else if(type == "cattle") {
    			return new Cattle();
    		} else if(type == "sheep") {
    			return new Sheep();
    		} else {
    			return new Chicken();
    		}
    	}
    }
    

    要使用该工厂类创建不同的 Animal产品,可以按照下面的步骤来使用:

    (1)创建工厂类Farm1.java的一个实例 farm。
    (2)传递不同的type 参数创建不同的 Animal 产品对象。

    可以调用每个 Animal的 sale()函数来计算销售价格和总收入,测试程序如下所示:

    测试类FarmlTest.java

    package creation.factorymethod;
    
    public class FarmlTest {
    
    	public static void test(int countl, int count2, int count3, int count4){
    		//创建工厂实例
    		FarmI farm = new Farml();
    		//生产对象
    		Animal animal1 = farm.produce("pig");
    		Animal animal2 = farm.produce("chicken");
    		Animal animal3 = farm.produce("cattle");
    		Animal animal4 = farm.produce("sheep");
    		
    		/计算收入
    		int money1 = animal1.sale()* count1;
    		int money2 = animal2.sale()* count2;
    		int money3 = animal3.sale( * count3;
    		int money4 = animal4.sale()* count4;
    		
    		System.out.println("Framl养猪收入:"+money1);
    		System.out.println("Framl养鸡收入:"+money2);
    		System.out.println("Framl养牛收入:"+ money3);
    		System.out.println("Framl养羊收入:"+money4);
    		
    		// 计算总收入
    		int sum = moneyl + money2 + money3 + money4;
    		System.out.println("Framl总收入:"+sum);
    	}
    
    	public static void main(String[] args) {
    		Farm1Test.test(20,1000,10,50);
    	}
    
    
    

    运行该程序的结果输出是:

    Fram1养猪收入:40000
    Framl养鸡收入:45000
    Framl养牛收入:76000
    Framl养羊收入:52500
    Fram1总收入:213500
    

    二、多个工厂方法模式

    对于第一种工厂类 Farm1.java 的函数 produce(,在每次调用该函数时必须传递一个类型参数。这种工厂类还显得比较稚嫩,因为当传递参数错误时,就不能够正确地创建产品。

    为了避免这一点不足,可以对该工厂进行改进,为该工厂类提供多个工厂方法,分别创建不同的产品对象,这就是多个工厂方法模式,其结构如下图所示。

    在这里插入图片描述
    在工厂类 Farm2.java中,它提供了多个工厂方法用来创建不同的 Animial 产品对象。

    • producePig():创建 Pig 对象。
    • produceChicke():创建 Chicken 对象
    • produceCattle():创建 Cattle 对象。
    • produceSheep():创建 Sheep 对象。

    该工厂类的代码如下程序:

    package creation.factorymethod;
    /**
    * @author Minggg
    * 多个工厂方法模式
    */
    public class Farm2{
    
    	public Animal producePig(){
    		return new Pig();
    	}
    	
    	publie Animal produceChicken(){
    		return new Chicken();
    	}
    	
    	public Animal produceCattle(){
    		return new Cattle();
    	}
    	
    	publie Animal produceSheep(){
    		return new Sheep();
    	}
    }
    

    此时我们再改造测试类,使用工厂类Farm2来分别创建4个不同的产品,不同之处如下程序所示:

    测试类Farm2Test.java

    package creation.factorymethod;
    
    public class Farm2Test {
    
    	public static void test(int countl, int count2, int count3, int count4) {
    		//创建工厂实例
    		Farm2 farm = new Farm2();
    		/ 生产对象
    		Animal animal1 = farm.producePig();
    		Animal animal2 = farm.produceChicken();
    		Animal animal3 = farm.produceCattle();
    		Animal animal4 = farm.produceSheep();
    		
    		/ 计算收入
    		int money1 = animal1.sale() * count1;
    		int money2 = animal2.sale() * count2;
    		int money3 = animal3.sale() * count3;
    		int money4 = animal4.sale() * count4;
    		
    		System.out.printIn("Fram2养猪收入:"+moneyl);
    		System.out.printin("Fram2 养鸡收入:"+money2);
    		System.out,println("Fram2 养牛收入:" + money3);
    		System.out.println("Fram2 养羊收入:"+money4);
    		
    		//计算总收入
    		int sum = moneyl + money2 + money3 + money4;
    		System.out.println("Fram2 总收入:" + sum);
    	}
    
    	public static void main(String[] args) {
    		Farm2Test.test(20,1000,10,50);
    	}
    }
    
    

    与普通的工厂方法模式不同的是,这里在使用Farm2创建产品时不需要输入参数,直接调用不同的工厂方法即可创建出各自的产品,显然使得代码更加优美了。

    三、静态工厂方法模式(简单工厂模式)

    经过以上的改进,使得工厂类更优美了,但是还有些美中不足。因为,我们在每一次创建 Animal实例需要使用工厂类时,都需要创建一个工厂对象。此时可以使用静态工厂方法模式,将工厂方法置为静态的,可以直接引用工厂类的方法来创建产品,结构如下图所示。

    在这里插入图片描述
    静态工厂方法模式又称为简单工厂模式,此时的工厂类如下程序所示:

    package creation.factorymethod;
    /**
    * @author Minggg
    * 简单工厂模式(静态工厂方法模式)
    */
    public class Farm3{
    	
    	public static Animal producePig() {
    		return new Pig();
    	}
    	
    	public static Animal produceChicken() {
    		retum new Chicken();
    	}
    	
    	public static Animal produceCattle() {
    		return new Cattle();
    	}
    	
    	public static Animal produceSheep() {
    		return new Sheep():
    	}
    }
    

    此时不需要创建工厂类的实例,可以直接引用静态方法来创建Animal产品,如下程序所示:

    package creation.factorymethod;
    
    public class Farm3Test {
    	public static void test(int countl, int count2, int count3, int count4){
    		// 生产对象
    		Animal animal1 = Farm3.producePig();
    		Animal animal2 = Farm3.produceChicken();
    		Animal animal3 =Farm3.produceCattle();
    		Animal animal4 = Farm3.produceSheep();
    		
    		//计算收入
    		int moneyl = animal1.sale() * count1;
    		int money2 = animal2.sale() * count2;
    		int money3 = animal3.sale() * count3;
    		int money4 = animal4.sale() * count4;
    		
    		System.out.printIn("Fram3 养猪收入:"+ money1);
    		System.out.println("Fram3 养鸡收入:"+ money2);
    		System,out.println("Fram3 养牛收入:"+ money3);
    		System.out.println("Fram3 养羊收入:"+ money4);
    		
    		// 计算总收入
    		int sum = money1 + money2 + money3 + money4;
    		System.out,printIn("Fram3 总收入:"+ sum);
    	}
    
    	public static void main(String[] args) {
    		Farm3Testtest(20,1000,10,50);
    	}
    
    }
    

    四、何时使用工厂方法模式

    工厂方法模式的核心是工厂类,这个类包含了创建产品的决策策略,它可以决定如何和何时创建什么产品对象。

    工厂方法模式应用的应用场景:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。如下图所示为产品结构:

    在这里插入图片描述
    以上我们讲解了3种工厂方法模式,经过逐步的改造,我们会发现第三种方式是比较优美的,因为它不需要创建工厂实例,而且可以创建多个产品,因此通常我们都会选用静态工厂方法模式来进行产品的创建。

    五、Java中的应用–Swing中的静态工厂类BorderFactory

    在 Java 的 Swing 包 javax.swing 中,需要创建多个不同的边界对象,这些边界类拥有一个共同的接口 Border,符合工厂方法模式应用的场景,如下图所示。
    在这里插入图片描述

    于是 Swing 中提供了一个工厂类 BorderFactory来创建不同的边界对象,它采用的是第三种静态工厂方法模式,在该工厂类中包含多个静态方法,分别用于创建不同类习惯的边界对象,例如下程序所示:

    Swing中的静态工厂类BorderFactory.java

    package javax.swing;
    
    import java.awt.Color;
    import java.awt.Font;
    import javax.swing.JComponent;
    import javax.swing.border.* ;
    
    public class BorderFactory {
    
    	public statie Border createLineBorder(Color color) {
    		return new LineBorder(color, 1);
    	}
    	public statie Border createLineBorder(Color color, int thickness){
    		return new LineBorder(color, thickness);
    	}
    
    	static final Border sharedRaisedBevel = new BevelBorder(BevelBorder.RAISED);
    	static final Border sharedLoweredBevel = new BevelBorder(BevelBorder.LOWERED);
    
    	publie static Border createRaisedBevelBorder()(
    		return createSharedBevel(BevelBorder RAISED);
    	}
    	
    	public statie Border createLoweredBevelBorder(){
    		return createSharedBevel(BevelBorder.LOWERED);
    	}
    	
    	publie static Border createBevelBorder(int type) {
    		return createSharedBevel(type);
    	}
    	
    	public statie Border createBevelBorder(int type, Color highlight, Color shadow){
    		return new BevelBorder(type, highlight, shadow);
    	}
    
    	public static Border createBevelBorder(int type, Color highlightOuter, Color highlightlnner, Color shadowOuter, Color
    shadowInner){
    		return new BevelBorder(type, highlightOuter, highlightlnner, shadowOuter, shadowlnner);
    	}
    	
    	static Border createSharedBevel(int type) {
    		if(type == BevelBorder.RAISED){
    			return sharedRaisedBevel;
    		} else if(type == BevelBorder.LOWERED){
    			return sharedLoweredBevel;
    		}
    		return null;
    	}
    	
    	static final Border sharedEtchedBorder = new EtchedBorder();
    	private static Border sharedRaisedEtchedBorder;
    	
    	public static Border createEtehedBorder() {
    		return sharedEtchedBorder;
    	}
    	
    	public static Border createEtchedBorder(Color highlight, Color shadow)
    		return new EtchedBorder(highlight, shadow);
    	}
    
    	public statie Border createEtchedBorder(int type) {
    		switch (type){
    			case EtchedBorder.RAISED:
    				if (sharedRaisedEtchedBorder == null){
    					sharedRaisedEtchedBorder = new EtchedBorder(EtchedBorder.RAISED):
    				}
    				return sharedRaisedEtchedBorder;
    			case EtchedBorder.LOWERED:
    				return sharedEtchedBorder;
    			default:
    				throw new IllegalArgumentException("type must be one of EthedBorder.RAISED or EtchedBorder.LOWERED"):
    		}
    	}
    
    	publie static Border createEtchedBorder(int type, Color highlight, Color shadow) {
    		return new EtchedBorder(type, highlight, shadow);
    	}
    
    	public statie TitledBorder createTitledBorder(String title) {
    		return new TitledBorder(title);
    	}
    	
    	public static TitledBorder createTitledBorder(Border border) {
    		return new TitledBorder(border);
    	}
    
    	public statie TitledBorder ereateTitledBorder(Border border, String title){
    		return new TitledBorder(border, title);
    	}
    	
    	public statie TitledBorder createTitledBorder(Border border, String title, int titleJustification, int titlePosition) {
    		return new TitledBorder(border, title, titleJustifieation, titlePosition);
    	}
    
    	public static TitledBorder createTitledBorder(Border border, String title, int titleJustification int titlePosition, Font titleFont){
    		return new TitledBorder(border, title, titleJustification, titlePosition, titleFont);
    	}
    	
    	public static TitledBorder createTitledBorder(Border border, String title, int titleJustifcation, int titlePosition, Font titleFont, Color titieColor){
    		return new TitledBorder(border, title, titleJustification, titlePosition, titleFont, titleColor);
    	}
    	
    	final static Border emptyBorder = new EmptyBorder(0, 0, 0, 0);
    	public static Border createEmptyBorder(){
    		return emptyBorder;
    	}
    
    	public statie Border createEmptyBorder(int top, int left, int bottom, int right) {
    		return new EmptyBorder(top, left, bottom, right);
    	}
    	
    	public static CompoundBorder createCompoundBorder()(
    		return new CompoundBorder;
    	}
    	
    	publie statie CompoundBorder createCompoundBorder(Border outsideBorder, Border insideBorder) {
    		return new CompoundBorder(outsideBorder, insideBorder);
    	}
    	
    	public static MatteBorder createMatteBorder(int top, int left, int bottom, int right, Color color) {
    		return new MatteBorder(top, left, bottom, right, color);
    	}
    	
    	public static MatteBorder createMatteBorder(int top, int left, int bottom, int right, lcon tilelcon) {
    		return new MatteBorder(top, left, bottom, right, tilelcon);
    	}
    
    }
    

    以上的代码的静态函数才属于本文所讲解的工厂方法模式,还有一些使用了单例模式创建的唯一性实例变量。

  • 相关阅读:
    java代码审计的点
    效率技巧│十分钟学会 xmind 思维导图的使用
    掌握JavaScript的练习之道:十个手写函数让你信手拈来!
    抛砖系列之k8s HorizontalPodAutoscaler(HPA)
    MySQL 一键安装 (支持8.0.16-8.0.30)
    从IoTDB的发展回顾时序数据库演进史
    Linux 系统执行ls 命令出现 Input/output error 解决妙招
    计算数组中每个元素的立方根numpy.cbrt()
    ELK日志收集系统(四十九)
    供需采购报价小程序系统
  • 原文地址:https://blog.csdn.net/qq_35885952/article/details/139597046