1.简单工厂模式的定义
简单工厂模式 (Simple Factory Pattern):定义一个工厂类,内含一个静态工厂方法,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
-
实现简单,以前写代码的时候也经常用这个模式,因为过于简单,甚至不是GoF 23个设计模式中的一员…
-
通俗的解释:Simple Factory模式根据提供给它的数据,返回几个可能类中的一个类的实例。通常它返回的对象所属的类都有一个公共的父类和一些公共的方法。
-
它属于类创简单工厂模式
-
如果需要什么对象,只需要传给工厂类一个正确的参数,就可以获取到所需要的对象,而无须知道其创建细节。
2.角色分工及结构
- 具体产品类(ConcreteProduct):将需要创建的各种不同产品对象的相关代码封装到具体产品类中
- 抽象产品类(Product):将具体产品类公共的代码进行抽象和提取后封装在一个抽象产品类中
- 工厂类(Factory):提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入参数的不同创建不同的具体产品对象
- 客户端:只需调用工厂类的工厂方法并传入相应的参数即可得到一个创建型模式
3.优缺点
优点:
- 工厂类含有必要的判断逻辑,可以决定在什么时候“创建”哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品。简单工厂模式通过这种做法实现了对对象创建和使用的分离。
缺点:
- 因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
- 违反开放/封闭原则: 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
- 另外,简单工厂模式通常使用静态工厂方法,这使得无法由子类继承,造成工厂角色无法形成基于继承的等级结构。
4.适用环境
- 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂;
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
简单工厂模式的延申----工厂方法模式,继承了简单工厂模式的优点,同时还弥补了简单工厂模式的缺陷,应该是考试的重点把。。
5.工厂方法模式的定义
工厂方法模式:定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
- 类创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
- 工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
- 在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
- 在Factory Method模式中,工厂类与产品类往往具有平行的等级结构,它们之间一一对应。
6.角色分工及结构
- 抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建对象的具体工厂类必须实现这个接口。
- 具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建具体产品对象。
- 抽象产品(Product)角色:工厂方法模式所创建的对象的超类,也就是具体产品对象的共同父类或共同拥有的接口。
- 具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。每个具体产品有专门的具体工厂创建,它们之间有一一对应的关系。
7.优缺点
优点
- 模式的核心是一个抽象工厂类,而不是像简单工厂模式把核心放在一个具体类上;
- 解除了简单工厂模式中对象创建代码的耦合,在系统中加入新产品时,完全符合开放/封闭原则。
缺点
- 系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,会给系统带来一些额外的开销;
- 增加了系统的抽象性和理解难度;
- 选择判断的问题还是存在的,把简单工厂的内部逻辑判断移到了客户端代码来进行,增加功能时,需要修改客户端。–可以用配置文件+反射改进
8.适用环境
- 客户端不知道它所需要的对象的类。在工厂方法模式中,客户不需要知道具体产品类的类品,只需知道所对应的工厂即可,具体产品对象由具体工厂创建,可将具体工厂类的类名存储在配置文件或数据库中。
- 抽象工厂类通过其子类指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使系统更容易扩展。
9.代码实现
有一个地方一定要记录一下:通过引入配置文件来解耦(书上用C#写的,用Java实现一下)
工程结构:
配置文件:
测试类(客户端):
/**
* 测试类
*/
public class test {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
/*Factory factory;
factory = new BMWCarFactory();
Car car = factory.FactoryMethod();
car.MethodDiff();
factory = new BenzCarFactory();
Car car2 = factory.FactoryMethod();
car2.MethodDiff();*/
//如果需要增加一个新的工厂类,比如说要生产奥迪品牌的车,那么在客户端test中仍然需要修改,不符合开闭原则
//下面通过引入配置文件来解决这个问题
Factory carFactory = null;
Car car;
//创建Properties集合对象
Properties prop = new Properties();
//创建一个文件流,加载prop.txt中的内容
prop.load(new FileReader("src/FactorySample/prop.txt"));
// 可以用下面这种方式来获得prop中所有的键,本例中之间用getProperty获得key
//Set<String> set = prop.stringPropertyNames();
//用value拼出工厂的全类名,FactorySample.BMWCarFactory,这要求工厂的工程路径要在同一个包下,否则拼的时候太麻烦,还是需要修改类中的内容
String value = "FactorySample." + prop.getProperty("factory");
try {
//利用反射机制获得工厂类的对象
carFactory = (Factory) Class.forName(value).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
car = carFactory.FactoryMethod();
car.MethodDiff();
}
}
这样修改工厂的时候只需要修改配置文件就可以了,源码不需要任何改动