软件设计模式-工厂模式
阅读数:109 评论数:0
跳转到新版页面分类
架构学
正文
设计原则:要依赖抽象,不要依赖具体类。
这个原则听起来很像是“针对接口编程,不针对实现编程”,然而这里更强调“抽象”,不能让高层组件依赖底层组件,而且,不管高层或低层组件,“两者”应该依赖于抽象。
一、简单工厂
1、模式描述
这其实不是一个设计模式,反而比较像一种编程习惯。
利用一个静态方法定义一个简单工厂是很常见的方法,常称为静态工厂。虽然可以在使用方法时,不用实例化方法,但也不能通过继承来改变创建方法的行为。
简单工厂模式实质是由一个工厂类根据传入的参数,决定应该创建哪一个产品类对象。
2、示例
(1)写一个简单的Car汽车接口,有不同的实现子类。
// 汽车接口
public interface Car {
void run();
}
// 汽车产品一:实现类--BMW
public class Bmw implements Car{
@Override
public void run() {
System.out.println("----宝马车启动----");
}
}
// 汽车产品二:实现类--Benz
public class Benz implements Car{
@Override
public void run() {
System.out.println("----奔驰车启动----");
}
}
// 汽车产品三:实现类--Audi
(2)静态工厂类
public class CarStaticFactory {
public static Car getCar(String carName){
if (carName.equals("BMW")){
return new Bmw();
}else if (carName.equals("Benz")){
return new Benz();
}
return null;
}
}
虽然这种方式分离了创建和使用,用户无需关心创建的过程,降低了耦合,但违背了设计模式的“开闭原则”,如果后期需要增加更多的产品类,则必须对工厂类进行修改。
(3)使用反射进行改进
为了解决每增加一个产品,就得修改工厂类,增加一个else if分支,使用反射进行改进。
public class CarStaticFactory {
public static Car getCar(String carName){
if (carName.equals("BMW")){
return new Bmw();
}else if (carName.equals("Benz")){
return new Benz();
}
return null;
}
// 通过反射获取类实例
public static Car getCarByReflect(String classPath){
Car car = null;
try {
Class clazz = Class.forName(classPath);
//创建对象
car = (Car) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return car;
}
}
测试类
public class Test {
public static void main(String[] args) {
// 静态工厂
// Car car = CarStaticFactory.getCar("BMW");
Car car = CarStaticFactory.getCarByReflect("com.example.demo.factory.Bmw");
car.run();
}
}
我们在实际如此使用时,会发现类的全路径会耦合在使用代码里。
(4)使用配置文件再次改造
增加配置文件,读取配置文件获取对应的类路径变量,再反射创建实例。
创建一个配置文件applicationContext.properties文件。
bmw=com.example.demo.factory.Bmw
benz=com.example.demo.factory.Benz
/**
* @description: 模拟bean工厂类
* @author: stwen_gan
* @date:
**/
public class BeanFactory {
/**
* 通过properties类获取配置文件中的配置
*/
private static Properties properties = new Properties();
static {
try {
//1. 获得IO输入流
InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.properties");
//2. 加载流
properties.load(inputStream);
//3. 关闭流
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Car getCarByName(String beanName){
Car car = null;
try {
Class clazz = Class.forName(properties.getProperty(beanName));
//创建对象
car = (Car) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return car;
}
}
这样我们就实现了一个通用的工厂模式。
其实,Spring在启动时通过xml、JavaConfig、注解扫描等方式注册bean,我们需要某个bean实例时,就可以通过调用getBean方法从ApplicationContext中获取容器的bean对象。Spring中BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,所以说,虽然简单的静态工厂模式有缺陷,但正因为它简单方便,可通过一定的改造,在某些场景更实用方便。
二、工厂方法模式
1、模式描述
定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
可以认为工厂方法是简单工厂的进一步延伸,这是因为简单工厂违反了开放-封闭原则,而工厂方法却没有这个问题。
将产品的“实现”从“使用”中解耦,同时可以定义一个默认的工厂方法来产生某些具体的产品,这样一来,即使创建者没有任何子类,依然可以创建产品。简单工厂把全部的事情,在一个地方都处理完,然而工厂方法却是创建一个框架,让子类决定如何实现。将创建对象的代码集中在一个对象或方法中,可以避免代码中的重复,并且更方便以后的维护。
在抽象的Creator中,任何其他实现的方法,都可能使用到这个工厂方法所造出来的产品,但只有子类真正实现这个工厂方法并创建产品。其中的子类的确看起来很像简单工厂。
2、示例
(1)创建工厂子类
// 抽象接口
public interface ICarFactory {
Car getCarByFactory();
}
// bmw 工厂子类 (某一类型的工厂,只生产bmw车型)
public class BmwFactory implements ICarFactory{
@Override
public Car getCarByFactory() {
return new Bmw();
}
}
// benz 工厂子类 (某一类型的工厂,只生产benz车型)
public class BenzFactory implements ICarFactory{
@Override
public Car getCarByFactory() {
return new Benz();
}
}
// ....
(2)测试
public class Test {
public static void main(String[] args) {
// // 静态工厂
// Car car = CarStaticFactory.getCar("BMW");
// car.run();
// 工厂方法
Car car = new BmwFactory().getCarByFactory();
car.run();
}
}
三、抽象工厂模式
1、模式描述
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
2、示例
(1)创建工厂类
/**
* @description: 抽象工厂--可生产不同产品组产品
* @author: stwen_gan
* @date:
**/
public interface Factory {
Car getCarByFactory();
Plane getPlaneByFactory();
// 其他产品组。。。
}
// 工厂一:可生产宝马汽车和客机
public class FactoryOne implements Factory{
@Override
public Car getCarByFactory() {
return new Bmw();
}
@Override
public Plane getPlaneByFactory() {
return new AirPlane();
}
}
// 工厂二:可生产奔驰汽车和战斗机
public class FactoryTwo implements Factory{
@Override
public Car getCarByFactory() {
return new Benz();
}
@Override
public Plane getPlaneByFactory() {
return new BattlePlane();
}
}
(2)测试
public class Test {
public static void main(String[] args) {
// 抽象工厂
Car car1 = new FactoryOne().getCarByFactory();
car1.run();
Plane plane1 = new FactoryOne().getPlaneByFactory();
plane1.fly();
Car car2 = new FactoryOne().getCarByFactory();
car2.run();
Plane plane2 = new FactoryOne().getPlaneByFactory();
plane2.fly();
}
}