「这是我参与2022首次更文挑战的第31天,活动详情查看:2022首次更文挑战」
模式定义:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod 使得一个类的实例化延迟到子类
简单工厂
假设我们有一个动物园,饲养员每天要喂养各种动物,但是小动物比较挑食,因此饲养员就需要记住每种动物喜欢吃什么食物,这样就可以有针对性的喂养啦,代码如下:
package com.jony.factory;
public class SimpleFactoryMethod {
public static void main(String[] args) {
//准备喂养小狗
Animal dog=new Dog();
dog.eat();
//准备喂养小猫
Animal cat=new Cat();
cat.eat();
}
}
interface Animal{
public void eat();
}
class Dog implements Animal{
@Override
public void eat() {
System.out.println("小狗爱啃骨头");
}
}
class Cat implements Animal{
@Override
public void eat() {
System.out.println("小猫爱吃鱼");
}
}
好景不长,饲养员嫌工资低,辞职不干了,然后招聘了一个新的饲养员,但是这个饲养员对各种动物喜欢吃啥不知道,因此我们得帮他实现一个简单的方法,只要饲养员告诉我们啥动物,我们就告诉饲养员这个动物喜欢吃啥
package com.jony.factory;
public class SimpleFactoryMethod {
public static void main(String[] args) {
Animal animal=SimpleFactory.animalFactory("小狗");
animal.eat();
}
}
interface Animal{
public void eat();
}
class Dog implements Animal{
@Override
public void eat() {
System.out.println("小狗爱啃骨头");
}
}
class Cat implements Animal{
@Override
public void eat() {
System.out.println("小猫爱吃鱼");
}
}
class SimpleFactory{
public static Animal animalFactory(String animal){
if("小狗".equals(animal)){
return new Dog();
}else if("小猫".equals(animal)){
return new Cat();
}else{
return null;
}
}
}
执行结果如下:
这样饲养员就不用自己亲自记录各种小动物喜欢吃啥,直接告诉工厂准备喂养啥动物,然后就可以实现小动物喜欢吃啥了。
特点
1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。
缺点
1 扩展性差(想增加一种动物外,除了新增一个动物产品类,还需要修改工厂类方法)不符合开闭原则
2 不同的产品需要不同额外参数的时候不支持。
工厂方法模式
后期动物园发展壮大,又引入了一些飞行动物,现有的饲养员无法完成这么大工作量,因此就需要新的方案。
这样我们就可以创建两个工厂,小动物有小动物的工厂(食草动物),飞行动物有飞行动物的工厂(食肉动物)。
产品方面
Animal SmallAnimal FlyAnimal
interface Animals{
public void eat();
}
class SmallAnimals implements Animals{
@Override
public void eat() {
System.out.println("喜欢吃草");
}
}
class FlyAnimal implements Animals{
@Override
public void eat() {
System.out.println("喜欢吃肉");
}
}
工厂:
Factory SmallFactory FlyFactory
interface Factory{
public Animals getAnimal();
}
class SmallFactory implements Factory{
@Override
public Animals getAnimal() {
return new SmallAnimals();
}
}
class FlyFactory implements Factory{
@Override
public Animals getAnimal() {
return new FlyAnimal();
}
}
测试方法:
class Test{
public static void main(String[] args) {
SmallFactory smallFactory=new SmallFactory();
smallFactory.getAnimal().eat();
FlyFactory flyFactory=new FlyFactory();
flyFactory.getAnimal().eat();
}
}
根据例子可以描述为:一个抽象产品类,可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例
优点:
- 符合开-闭原则:新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
- 符合单一职责原则:每个具体工厂类只负责创建对应的产品
缺点:
- 增加了系统的复杂度:类的个数将成对增加
- 增加了系统的抽象性和理解难度
- 一个具体工厂只能创建一种具体产品
抽象工厂模式
定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类;具体的工厂负责实现具体的产品实例。
解决的问题:每个工厂只能创建一类产品(工厂方法模式)
抽象工厂模式与工厂方法模式最大的区别:抽象工厂中每个工厂可以创建多种类的产品;而工厂方法每个工厂只能创建一类
举个例子,我们去买水果,需要购买 苹果和菠萝,苹果有河北苹果,也有山东苹果,那么我们购买的时候就可以进行选择,那有一天我们想购买河南苹果,如果更好的创建工厂模式呢?
首先创建水果接口,苹果/梨抽象类,及各地区的实现方法
interface Fruit{
public void buy();
}
abstract class Apple implements Fruit{
public abstract void buy();
}
abstract class Pear implements Fruit{
public abstract void buy();
}
class HeBeiApple extends Apple{
@Override
public void buy() {
System.out.println("购买河北苹果");
}
}
class ShanDongApple extends Apple{
@Override
public void buy() {
System.out.println("购买山东苹果");
}
}
class HeBeiPear extends Pear{
@Override
public void buy() {
System.out.println("购买河北梨");
}
}
class ShanDongPear extends Pear{
@Override
public void buy() {
System.out.println("购买山东梨");
}
}
创建抽象工厂及具体工厂
//抽象工厂
interface FruitFactory{
public Fruit getApple();
public Fruit getPear();
}
//具体工厂-河北工厂
class HeBeiFactory implements FruitFactory{
@Override
public Fruit getApple() {
return new HeBeiApple();
}
@Override
public Fruit getPear() {
return new HeBeiPear();
}
}
//具体工厂-山东工厂
class ShanDongFactory implements FruitFactory{
@Override
public Fruit getApple() {
return new ShanDongApple();
}
@Override
public Fruit getPear() {
return new ShanDongPear();
}
}
具体实现
public static void main(String[] args) {
//创建河北工厂
HeBeiFactory heBeiFactory=new HeBeiFactory();
Fruit apple=heBeiFactory.getApple();
apple.buy();
Fruit pear=heBeiFactory.getPear();
pear.buy();
//创建山东工厂
ShanDongFactory shanDongFactory=new ShanDongFactory();
Fruit sdApple=shanDongFactory.getApple();
sdApple.buy();
Fruit sdPear=shanDongFactory.getPear();
sdPear.buy();
}
这样当我们想创建河南工厂的时候,就不需要修改抽象工厂,只需要创建河南工厂即可。
在什么情况下应当使用抽象工厂模式
1.一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
2.这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
3.同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
4.系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
抽象工厂模式的优点
- 分离接口和实现
客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦。
- 使切换产品族变得容易
因为一个具体的工厂实现代表的是一个产品族,比如上面例子的从河北到山东只需要切换一下具体工厂。
抽象工厂模式的缺点
- 不太容易扩展新的产品
如果需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。(比如每个地区,不仅生成苹果和梨,还会生成香蕉)
抽象工厂举例二
我们在开发项目的时候,代码需要连接数据库,并进行CRUD.项目后期可能要兼容多种数据库操作,因此我们就需要用到抽象工厂的方式,将目前可知的数据源进行抽象工厂方式创建,以后万一有其他数据源也不必修改代码,只需要创建自己的工厂即可,代码如下:
数据库连接及执行命令的工厂实现
//首先创建已知的产品--数据库连接+执行数据库命令
//创建数据库连接
interface IConnection{
public void connected();
}
//执行数据库命令
interface ICommond{
public void commond();
}
//创建mysql具体连接实现
class MysqlConnection implements IConnection{
@Override
public void connected() {
System.out.println("mysql connection...");
}
}
//创建mysql具体执行命令实现
class MysqlCommond implements ICommond{
@Override
public void commond() {
System.out.println("mysql commond...");
}
}
//创建数据库连接及执行命令工厂
interface DBFactory{
public void connection();
public void commond();
}
//创建mysql具体实现工厂
class MysqlDBUtils implements DBFactory{
@Override
public void connection() {
new MysqlConnection().connected();
}
@Override
public void commond() {
new MysqlCommond().commond();
}
}
假如这时候Oracle数据源也需要支持,我们只需要添加Oracle相关实现,不需要修改之前的代码,即可实现如下:
//首先创建已知的产品--数据库连接+执行数据库命令
//创建数据库连接
interface IConnection{
public void connected();
}
//执行数据库命令
interface ICommond{
public void commond();
}
//创建mysql具体连接实现
class MysqlConnection implements IConnection{
@Override
public void connected() {
System.out.println("mysql connection...");
}
}
//创建oracle
class OracleConnection implements IConnection{
@Override
public void connected() {
System.out.println("oracle connection...");
}
}
//创建mysql具体执行命令实现
class MysqlCommond implements ICommond{
@Override
public void commond() {
System.out.println("mysql commond...");
}
}
class OracleCommond implements ICommond{
@Override
public void commond() {
System.out.println("oracle commond...");
}
}
//创建数据库连接及执行命令工厂
interface DBFactory{
public void connection();
public void commond();
}
//创建mysql具体实现工厂
class MysqlDBUtils implements DBFactory{
@Override
public void connection() {
new MysqlConnection().connected();
}
@Override
public void commond() {
new MysqlCommond().commond();
}
}
class OracleDBUtils implements DBFactory{
@Override
public void connection() {
new OracleConnection().connected();
}
@Override
public void commond() {
new OracleCommond().commond();
}
}
执行代码
public static void main(String[] args) {
DBFactory dbFactory=new MysqlDBUtils();
dbFactory.connection();
dbFactory.commond();
DBFactory dbFactory1=new OracleDBUtils();
dbFactory1.connection();
dbFactory1.commond();
}