抽象工厂模式
说到抽象工厂模式前,首先需要理解两个概念,一个是产品等级,一个是产品族。
产品等级
产品等级结构即产品的继承结构,如一个抽象类是键盘,其子类有狼蛛键盘、雷柏键盘、联想键盘,则抽象键盘与具体品牌的键盘之间构成了一个产品等级结构,抽象键盘是父类,而具体品牌的键盘是其子类。也就是说具有共同父类的对象为一个产品等级
产品族
产品族是指由*同一个工厂生产的,位于不同产品等级结构中的一组产品。如小米工厂生产的小米手机、小米电视,小米手机位于手机产品等级结构中,小米电视位于电视产品等级结构中,小米手机、小米电视构成了一个产品族。通俗的说就是,同一家工厂生产出来的不同产品等级构成一个产品族
抽象工厂与工厂模式的区别
工厂方法模式:一个抽象产品类,可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例。
区别:工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
定义
抽象工厂模式(Abstract Factory Pattern) 是一种比较常用的模式, 其定义如下:
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
翻译过来就是:为创建一组相关或相互依赖的对象提供一个接口, 而且无须指定它们的具体类。
类图结构
由类图可以看到,抽象工厂有两个子类,都实现了父类的createProudctA和createProductB两个方法,工厂1生产的A和B为一个产品族,工厂2生产的A和B又是另一个产品组,而A1和A2又是同一个产品等级
代码实现
假设现在小明想组装台电脑,市场上有很多电脑配件,小明希望用联想的键盘和Dell的鼠标组装一台自己的电脑。代码实现方式就是
抽象Pc工厂类
/**
*@DESCRIPTION 生产PC电脑的抽象工厂, 可以生产键盘和鼠标
*@AUTHOR SongHongWei
*@TIME 2018/8/12-17:12
*@PACKAGE_NAME test.factory._abstract
**/
public abstract class AbstractPcFactory
{
//生产一个鼠标
public abstract MouseProduct getMouse();
//生产一个键盘
public abstract keyBoardProduct getKeyBoard();
}
鼠标抽象类
/**
*@DESCRIPTION 抽象的鼠标类也可以是一个接口
*@AUTHOR SongHongWei
*@TIME 2018/8/12-15:27
*@PACKAGE_NAME test.factory.general
**/
public abstract class MouseProduct
{
/**
*@DESCRIPTION 打印鼠标的名称
*@AUTHOR SongHongWei
*@TIME 2018/8/12-17:12
*@CLASS_NAME MouseProduct
**/
public abstract void getMouserName();
}
键盘抽象类
/**
*@DESCRIPTION 抽象的键盘类也可以是一个接口
*@AUTHOR SongHongWei
*@TIME 2018/8/12-15:27
*@PACKAGE_NAME test.factory.general
**/
public abstract class keyBoardProduct
{
/**
*@DESCRIPTION 打印键盘的名称
*@AUTHOR SongHongWei
*@TIME 2018/8/12-17:12
*@CLASS_NAME MouseProduct
**/
public abstract void getKeyBoardName();
}
LenovoPc工厂类
/**
*@DESCRIPTION 联想鼠标工厂, 负责生产联想鼠标
*@AUTHOR SongHongWei
*@TIME 2018/8/12-15:30
*@PACKAGE_NAME test.factory.general
**/
public class LenovoPcFactory extends AbstractPcFactory
{
/*
* 生产一个联想鼠标
*/
@Override
public MouseProduct getMouse()
{
return new LenovoMouse();
}
/*
* 生产一个联想键盘
*/
@Override
public keyBoardProduct getKeyBoard()
{
return new LenovoKeyBoard();
}
}
DellPc工厂类
/**
*@DESCRIPTION 戴尔鼠标工厂, 负责生产戴尔鼠标
*@AUTHOR SongHongWei
*@TIME 2018/8/12-15:30
*@PACKAGE_NAME test.factory.general
**/
public class DellPcFactory extends AbstractPcFactory
{
/*
* 生产一个戴尔鼠标
*/
@Override
public MouseProduct getMouse()
{
return new DellMouse();
}
/*
*生产一个戴尔键盘
*/
@Override
public keyBoardProduct getKeyBoard()
{
return new DellKeyBoard();
}
}
Lenovo鼠标类
/**
*@DESCRIPTION 联想鼠标
*@AUTHOR SongHongWei
*@TIME 2018/8/12-15:28
*@PACKAGE_NAME test.factory.general
**/
public class LenovoMouse extends MouseProduct
{
@Override
public void getMouserName()
{
System.out.println("I'm mouse come from Lenovo...");
}
}
Lenovo 键盘类
/**
*@DESCRIPTION 联想键盘
*@AUTHOR SongHongWei
*@TIME 2018/8/12-15:28
*@PACKAGE_NAME test.factory.general
**/
public class LenovoKeyBoard extends keyBoardProduct
{
@Override
public void getKeyBoardName()
{
System.out.println("I'm keyboard come from Lenovo...");
}
}
Dell鼠标类
/**
*@DESCRIPTION 戴尔鼠标
*@AUTHOR SongHongWei
*@TIME 2018/8/12-15:28
*@PACKAGE_NAME test.factory.general
**/
public class DellMouse extends MouseProduct
{
@Override
public void getMouserName()
{
System.out.println("I'm mouse come from Dell...");
}
}
Dell键盘类
/**
*@DESCRIPTION 戴尔键盘
*@AUTHOR SongHongWei
*@TIME 2018/8/12-15:28
*@PACKAGE_NAME test.factory.general
**/
public class DellKeyBoard extends keyBoardProduct
{
@Override
public void getKeyBoardName()
{
System.out.println("I'm keyboard come from Dell...");
}
}
客户端调用
/**
*@DESCRIPTION ${END}
*@AUTHOR SongHongWei
*@TIME 2018/8/12-17:20
*@PACKAGE_NAME test.factory._abstract
**/
public class Client
{
public static void main(String[] args)
{
//用户希望自己组装台电脑,但是想用联想的键盘和Dell的鼠标
AbstractPcFactory pcFactory = new LenovoPcFactory();
//得到联想键盘
pcFactory.getKeyBoard().getKeyBoardName();
pcFactory = new DellPcFactory();
//得到Dell鼠标
pcFactory.getMouse().getMouserName();
}
}
输出结果
I'm keyboard come from Lenovo...
I'm mouse come from Dell...
Process finished with exit code 0
总结
抽象工厂模式的最大缺点就是产品族扩展非常困难, 为什么这么说呢? , 如果要增加一个产品显示器, 也就是说产品家族由原来的2个增加到3个, 看看我们的程序有多大改动吧! 抽象类AbstractPcFactory要增加一个方法getDisplay(), 然后两个实现类都要修改, 想想看, 这严重违反了开闭原则.但是一定要清楚, 是产品族扩展困难, 而不是产品等级。 在该模式下, 产品等级是非常容易扩展的, 增加一个产品等级, 只要增加一个工厂类负责新增加出来的产品生产任务即可。 也就是说横向扩展容易, 纵向扩展困难。
而抽象工厂的优点就是可以在类的内部对产品族进行约束。因为所谓的产品族,一般或多或少的都存在一定的关联,比如一台电脑只能接一个鼠标和键盘, 抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。