设计模式-2.工厂模式

前言:什么是工厂模式?

工厂模式就是将对象的创建交由工厂来实现,程序只管使用其中具体的方法即可。

我们为什么要使用工厂模式?

1.将对象的创建和对象的使用分开,降低耦合度,提供代码重复利用率;

2.后期对于创建对象的修改成本小。

虽然工厂模式有这么优势,但是并不是所有的场景都适用于工厂模式。我们总不能把所有的需要创建对象的地方都换成工厂模式吧?那就有点为了使用设计模式而使用工厂模式了。

那么什么场景下,适合使用工厂模式呢?

1. 对象的创建过程/实例化准备工作很复杂,需要初始化很多参数、查询数据库等。其中的参数设置错误,就比较影响客户的使用。

例如:

一个数据库工厂:可以返回一个数据库实例,可以是mysql,oracle等。

这个工厂就可以把数据库连接需要的用户名,地址,密码等封装好,直接返回对应的数据库对象就好。不需要调用者自己初始化,减少了写错密码等等这些错误。调用者只负责使用,不需要管怎么去创建、初始化对象。

2.类本身有好多子类,这些类的创建过程在业务中容易发生改变,或者对类的调用容易发生改变。

工厂模式从简单到复杂可以分为三大类,分别是简单工厂模式、工厂方法模式、抽象工厂模式。大家可以根据自己的应用场景来选择,下面进行逐一介绍。

1.简单工厂模式

有一个工厂类,负责产出产品。通过工厂类的一个方法返回产品(返回的类型是抽象产品类)。不过产品多种多样,具体的产品类要继承自这个抽象产品类。具体类图如下:

具体实现:

创建一个抽象产品类 Car

public interface Car {
	
	String getDriveCarName();
}

具体的产品类1:

public class BwmCar implements Car{

	@Override
	public String getDriveCarName() {
		// TODO Auto-generated method stub
		return "宝马";
	}

}

具体的产品类2:

public class AudiCar implements Car{

	@Override
	public String getDriveCarName() {
		// TODO Auto-generated method stub
		return "奥迪";
	}

}

工厂类:这里的实现方式有很多,我发现网上很多人对此还进行了区分,我对此也进行过查找。叫的名字多种多样,很容易混淆,我觉得没有区分必要,都是简单工厂的不同实现方式,只要工厂类只有一个,不为接口,就是简单工厂模式。(个人理解)

public class SimpleCarFactory {

	static final int TYPE_BM = 1; //也可以使用枚举内部类
	static final int TYPE_AD = 2; 
	//在这里具体的实现多种多样,getCar方法可以为静态也可以为非静态
	public static  Car  getCar(int type) { 
		switch (type) {
		
		case TYPE_BM:
			return new BwmCar();
		case TYPE_AD:
			return new AudiCar();
			
		default:
			return null;
		}
 }
	
///////////////////////////////////////////////第二种实现方式,可以为静态方法,也可以为非静态
	
		public static Car getBwmCar(){
			return new BwmCar();
		}
		
		public static AudiCar getAudiCar(){
			return new AudiCar();
		}
}

获取具体的产品,执行公共的方法:

public class Client {

	public static void main(String[] args) {
		//
        Car bwmCar = SimpleCarFactory.getCar(SimpleCarFactory.TYPE_BM);
        bwmCar.getDriveCarName();
        Car audiCar = SimpleCarFactory.getCar(SimpleCarFactory.TYPE_AD);
        audiCar.getDriveCarName();
        //或者
        SimpleCarFactory.getAudiCar().getDriveCarName();
        SimpleCarFactory.getBwmCar().getDriveCarName();
	}
}

总结:

//缺点:耦合性还很高
//每次要添加一种类型,工厂就要多加一个type。导致这个工厂类会变得非常繁重,甚至加入的这个type也可能再有变动。
//日积月累,代码几经易手,维护起来就会非常麻烦。

2.工厂方法模式

简单工厂模式只是让一类对象的创建让工厂管理了起来。但是对于软件设计中的开闭原则(即对扩展开放,对修改封闭)遵循的并不好。比如,我们要想增加一个产品,必须在工厂类中修改代码。而工厂方法模式就可以规避这个问题。当有新的产品时,增加一个具体的产品类继承自抽象产品类,再增加一个新的工厂类继承自抽象工厂类。然后让新的工厂类和新的产品类关联起来。这样就遵循了开闭原则。具体类图如下:

工厂方法模式虽然符合了开闭原则,但是代码量比以前大了。我们要想产新的产品,必须写一个新的工厂类,继承抽象工厂类。为了减少代码量,可以使用类模板(利用泛型,创建工厂类时,传入具体的产品类,以实现生产对应产品的作用),具体类图如下:

具体实现:

创建一个抽象产品类 Car

public interface Car {
	
	String getDriveCarName();
}

具体的产品类1:

public class BwmCar implements Car{

	@Override
	public String getDriveCarName() {
		// TODO Auto-generated method stub
		return "宝马";
	}

}

具体的产品类2:

public class AudiCar implements Car{

	@Override
	public String getDriveCarName() {
		// TODO Auto-generated method stub
		return "奥迪";
	}

}

创建一个抽象的产品工厂方法

public interface CarFactory {

	Car createCar();
}

各自产品的抽象方法

public class BwmCarFactory implements CarFactory{

	@Override
	public Car createCar() {
		// TODO Auto-generated method stub
		return new BwmCar();
	}

}
public class AudiCarFactory implements CarFactory{

	@Override
	public Car createCar() {
		// TODO Auto-generated method stub
		return new AudiCar();
	}

}

验证:

public class Client {

	public static void main(String[] args) {
		//
        Car bwmCar = new BwmCarFactory().createCar();
        bwmCar.getDriveCarName();
        Car audiCar = new AudiCarFactory().createCar();
        audiCar.getDriveCarName();
	}
}

这样一来,每次生产一种新类型,只需要再添加一个工厂就可以了。耦合性比起简单模式要松很多。

缺点:这个工厂使用太单一,一种工厂只能生产一种类型,这样代码量就增加了,下面是工厂方法模板的另一种实现。

public interface CarFactory {

	Car createCar(Class<? extends Car> clazz);
	
}
public class TempCarFactory implements CarFactory{

	@Override
	public Car createCar(Class<? extends Car> clazz) {
		 try {
	     return (Car)Class.forName(clazz.getName()).newInstance();
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	        return null;
	}
	
    }

测试:

public class Client {

	public static void main(String[] args) {
		//
	Car bwmCar = new TempCarFactory().createCar(BwmCar.class);
	Car audiCar = new TempCarFactory().createCar(AudiCar.class);
    
    System.out.println(bwmCar.getDriveCarName());
    System.out.println(audiCar.getDriveCarName());
	}
}

通过反射的方式,减少工厂实现类的创建

 

3. 抽象工厂模式(不做代码演示)

我们有时候需要的不仅仅是一类产品,可能是一套产品,比如,生产一支笔,不仅要生产笔芯,还有生产笔杆。

笔芯可以是A1厂的,也可以是A2厂的。笔杆可以是B1厂的,也可以是B2厂的。

那么我们的抽象工厂类,就不能只有一个create方法,应该有两个,一个制造A类产品,一类制造B类产品。

具体类图如下:

这种模式的弊端也是比较明显的,每增加一类新的产品,就要同时修改工厂接口和其实现类。我们可以将其优化成简单工厂模式。每类产品通过简单工厂类进行生产,然后调用者自由组合。这样工厂就只涉及一个简单工厂,没有继承关系了。

 

4.枚举方式

我们除了上述三种,还有一种,那就是枚举。
特征归纳:
1、枚举定义一个抽象方法,方法返回类型是子类共同要实现的Car接口。
2、枚举成员要实现抽象方法,并返回对象实例。
3、从扩展性来讲,新增子类,只需要新增成员,并实现抽象方法即可。
4、遵循“迪米特原则”,对于客户端调用利于读懂。
 

/**
 *
 * @desc 枚举方式实现
 * (1)、定义一个抽象方法
 * (2)、成员实现该抽象方法
 * 从扩展性来讲:
 * 1、增加一个产品类,需要增加一个枚举成员,相对静态工厂+反射方式,需要增加代码。
 */
public enum CarFactoryEnum {
    Audi{
        @Override
        Car create() {
            return new AudiCar();
        }
    },
    Bwm{
        @Override
        Car create() {
            return new BwmCar();
        }
    };

    abstract Car create();
}

测试:

public class Client {
    public static void main(String[] args) {
        Car audi = CarFactoryEnum.Audi.create();
        System.out.println(audi.getName());
        Car bwm = CarFactoryEnum.Bwm.create();
        System.out.println(bwm.getName());
    }
}

5.总结

工厂模式也是最常见的一种,不过我们使用Spring框架,就可以把Bean对象交由Bean容器管理。

 

发布了67 篇原创文章 · 获赞 25 · 访问量 3万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览