抽象工厂模式的基本概念
提供一个创建一系列相关或依赖对象的接口,而无需指定他们具体的类。
了解抽象工厂模式就需要先了解产品族以及产品等级结构的概念。
在抽象工厂模式中,一个具体工厂生产一个产品族,产品族即各种不同的产品的组合,例如正方形,圆形,椭圆形都是不同的,又有共同的抽象→形状。
例如加减乘除的算法都是不同的,又有共同的抽象→计算。
这些都是一个个的产品族,产品等级结构即一个具体产品的不同表现,如形状的颜色,大小。算法的参与运算个数。
一般情况下,
多少个产品等级结构,多少个工厂方法。
多少个产品族,多少个具体工厂。
以下是一张我引用的图:
引入与工厂模式相似的简单思想图:
和简单工厂模式于工厂方法模式比较,很容易看出
抽象程度上简单工厂模式<工厂方法<抽象工厂模式。
简单工厂模式:一个具体工厂生产多个具体产品。一个抽象产品。
工厂方法模式:一个具体工厂生产一个具体产品。多个抽象产品。
抽象工厂模式:一个具体工厂生产多个具体产品。多个抽象产品。
简单工厂模式与工厂方法模式见:http://blog.csdn.net/chijiandi/article/details/78841861
什么时候用抽象工厂模式
如果产品少而且基本不变动,用简单工厂模式。
如果产品单一,用工厂方法模式。
如果产品丰富,用抽象工厂模式。
同时,使用以上的几种模式都封装了对象创建的具体细节,使客户不用关注对象是如何来的,更关注于取得了对象。
抽象工厂模式再优化了工厂方法模式的细节上,因有了产品族的概念,在产品的生产上也会多出比工厂方法模式更多的类,这也是抽象带来的缺点。所以再实际开发中,一定要思考好该使用怎样的模式,或者说怎样的更简单的模式可以更好的胜任。考虑的不仅仅是可以怎么用,而是什么更适合用。
抽象工厂模式怎么用
我们根据之前的思想图,
一个抽象工厂模式需要有一个抽象的工厂,多个抽象的产品。
一个具体的工厂生产多个具体的产品。
以加减乘除为例:
需要一个两数的算法工厂能生产两数加法,两数乘法。
一个三数的算法工厂能生产三数加法,三数乘法。
那么,加法与乘法构成了一个产品族。
两数与三数构成了一个产品等级结构。
首先,我们需要一个两数产品的共同抽象:
/**
* @author : cjd
* @Description :抽象加法产品
* @create : 2018-01-03 10:19
**/
public interface AddCalc {
int getResult(int a, int b);
}
以及实现该抽象的具体产品:
/**
* @author : cjd
* @Description :两数具体加法产品
* @create : 2018-01-03 10:36
**/
class TwoNumberAdd implements TwoNumberCalc {
@Override
public int getResult(int a, int b) {
return a + b;
}
}
/**
* @author : cjd
* @Description :两数具体乘法产品
* @create : 2018-01-03 10:36
**/
class TwoNumberMultiply implements TwoNumberCalc {
@Override
public int getResult(int a, int b) {
return a * b;
}
}
同理得三数抽象产品与具体产品。
再根据其产品含有的产品等级结构(两数、三数)创建抽象的工厂:
/**
* @author : cjd
* @Description :抽象算法工厂
* @create : 2018-01-03 10:41
**/
public interface CalcFactory {
TwoNumberCalc createTwo();
ThreeNumberCalc createThree();
}
及具体的产品工厂:
/**
* @author : cjd
* @Description :具体加法工厂
* @create : 2018-01-03 10:48
**/
class AddFactory implements CalcFactory {
@Override
public TwoNumberCalc createTwo() {
return new TwoNumberAdd();
}
@Override
public ThreeNumberCalc createThree() {
return new ThreeNumberAdd();
}
}
/**
* @author : cjd
* @Description :具体乘法工厂
* @create : 2018-01-03 10:51
**/
class MultiplyFactory implements CalcFactory {
@Override
public TwoNumberCalc createTwo() {
return new TwoNumberMultiply();
}
@Override
public ThreeNumberCalc createThree() {
return new ThreeNumberMultiply();
}
}
客户端进行如下调用:
/**
* @author : cjd
* @Description :
* @create : 2018-01-03 10:52
**/
public class Main {
public static void main(String[] args) {
CalcFactory calcFactory;
//加法工厂
calcFactory = new AddFactory();
TwoNumberCalc twoAdd = calcFactory.createTwo();
ThreeNumberCalc threeAdd = calcFactory.createThree();
//乘法工厂
calcFactory = new MultiplyFactory();
TwoNumberCalc twoMultiply = calcFactory.createTwo();
ThreeNumberCalc threeMultiply = calcFactory.createThree();
System.out.println(twoAdd.getResult(1, 2) + " " + threeAdd.getResult(1, 2, 3));
System.out.println(twoMultiply.getResult(1, 2) + " " + threeMultiply.getResult(1, 2, 3));
}
}
如此,暴露出工厂便实现对产品的解耦,其缺点也显而易见,
放出最后的图自己体会:
记此,只为了提醒,慎用设计模式。
后记
对设计模式的学习我是参造着《大话设计模式》与网络资料的。
在《大话设计模式》里对抽象工厂模式有这样的几种优化处理:
1.通过简单工厂模式将繁琐的(抽象工厂+具体工厂A+具体工厂B)简化成一个具体工厂,在其中通过switch或if…else生成具体的产品,这样的做法能解除客户端对具体工厂的依赖。避免了一处改,处处改。
2.当产品族比较多且繁琐,大量的if…else就显得臃肿,此时可通过反射创建来避免大量的使用判断。
3.使用反射也不可避免会导致需要修改工厂时要修改程序的代码,所以通过配置文件来优化导入。
《大话设计模式》中并提供了这样的一种思想:
所有在用简单工厂模式的地方,都可以考虑使用反射技术来取出switch或if,解除分支判断带来的有些。
若有理解错误,感谢指出!