前言
工厂方法模式指定了抽象了产品的功能,等待具体产品去实现该功能,而工厂方法不管产品的任何实现,只需要按需返回指定产品类;但是当工厂类生产的产品差别很大的时候,要对每一个产品区别化时,我们需要去更改具体的Product类的方法,比如汽车的例子,我们两个车的引擎不一样,那么我们就要去改Product类里面的Engine的具体实现,这种情况下,抽象工厂模式就更适合。抽象工厂模式可以对产品的零部件做一个基类,然后列出所有需要的实现部件类,然后等待具体的产品Factory类去组装产品,这时候Factory不单单是之前的模式了,所以,每个产品都应该有一个工厂实现类,当然可以在统一工厂类,通过判断决定产生何种产品。通过这些描述我们也知道了抽象工厂模式的弊端,就是实现一个生产过程需要很多类,所以使用的时候还得考虑一下,因为如果工厂很大,或许java会报65535的错。
角色扮演
抽象工厂说起来很多类,但说到底还是4个主要类:
AbstractFactory: 抽象工厂角色,所有工厂类的抽象基类,只定义抽象方法。
ConcreteFactory:具体工厂角色,实现抽象方法,多个产品会有多个具体实现类。
AbstractProduct:抽象产品角色,定义一个产品的抽象基类,因为各个工厂类会有不同的产品类,所以这里并不需要实现。
ConcreteProduct: 具体产品角色,实现产品的具体功能。
其实这个和工厂方法模式很像,只是抽象方法增多了,易于对产品的扩展。
代码实现
生产奔驰汽车的时候发现汽车车型不同,汽车的发动机、内饰都不相同,那么抽象引擎、内饰、外壳为产品,可以使用抽象工厂模式。
定义奔驰汽车抽象工厂类:
package com.demo.abstractfactory;
/**
* Created by italkbb on 2017/12/14.
*/
public abstract class BenzCarFactory {
/**
* 装配内饰
* @return
*/
public abstract IDecoration addDecoration();
/**
* 装配引擎
* @return
*/
public abstract IEngine addEngine();
/**
* 装配外壳
* @return
*/
public abstract IShell addShell();
}
抽象工厂模式定义了汽车不同零件的装配方法,那么我们来列出所有的抽象产品类和具体产品类:
package com.demo.abstractfactory;
/**
* Created by italkbb on 2017/12/14.
*/
public interface IDecoration {
/**
* 内饰实现方法
*/
void docoration();
}
具体内饰实现类,内饰分为普通和豪华:
package com.demo.abstractfactory;
import android.util.Log;
/**
* Created by italkbb on 2017/12/14.
*/
public class NormalDecoration implements IDecoration {
// 类名,用于日志区分
public final static String CLASSNAME = NormalDecoration.class.getSimpleName();
@Override
public void docoration() {
Log.v(CLASSNAME,"普通内饰");
}
}
package com.demo.abstractfactory;
import android.util.Log;
/**
* Created by italkbb on 2017/12/14.
*/
public class LuxuryDecoration implements IDecoration {
// 类名,用于日志区分
public final static String CLASSNAME = LuxuryDecoration.class.getSimpleName();
@Override
public void docoration() {
Log.v(CLASSNAME,"豪华内饰");
}
}
同样,引擎分为国外跟国产类,同样的列出抽象类和具体类:
package com.demo.abstractfactory;
/**
* Created by italkbb on 2017/12/14.
*/
public interface IEngine {
/**
* 引擎装配
*/
void engine();
}
package com.demo.abstractfactory;
import android.util.Log;
/**
* Created by italkbb on 2017/12/14.
*/
public class DomesticEngine implements IEngine {
// 类名
public final static String CLASSNAME = DomesticEngine.class.getSimpleName();
@Override
public void engine() {
Log.v(CLASSNAME,"国产发动机");
}
}
package com.demo.abstractfactory;
import android.util.Log;
/**
* Created by italkbb on 2017/12/14.
*/
public class AbroadEngine implements IEngine {
// 类名
public final static String CLASSNAME = AbroadEngine.class.getSimpleName();
@Override
public void engine() {
Log.v(CLASSNAME,"进口发动机");
}
}
同样外壳也分为豪华和普通,但是因为代码都一样就不贴了。
接下来,我们要生产A级车和B级车,这时候相当于按需求拼装了,那么就会有两个工厂具体类:
package com.demo.abstractfactory;
/**
* Created by italkbb on 2017/12/14.
*/
public class BenzAFactory extends BenzCarFactory {
@Override
public IDecoration addDecoration() {
return new NormalDecoration();
}
@Override
public IEngine addEngine() {
return new DomesticEngine();
}
@Override
public IShell addShell() {
return new NormalShell();
}
}
package com.demo.abstractfactory;
/**
* Created by italkbb on 2017/12/14.
*/
public class BenzBFactory extends BenzCarFactory {
@Override
public IDecoration addDecoration() {
return new LuxuryDecoration();
}
@Override
public IEngine addEngine() {
return new AbroadEngine();
}
@Override
public IShell addShell() {
return new SportsShell();
}
}
这样产品的生产就完成了,使用的时候按需生产相关的类就行了,贴一下使用的代码:
package com.demo.abstractfactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import teltplay.example.com.kotlindemo.R;
public class AbstractFactoryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_abstract_factory);
// 生产A级车
BenzCarFactory mACarFactory = new BenzAFactory();
// 查询一下当前车辆信息
mACarFactory.addDecoration().docoration();
mACarFactory.addEngine().engine();
mACarFactory.addShell().shell();
// 生产B级车
BenzCarFactory mBCarFactory = new BenzAFactory();
// 查询一下当前车辆信息
mBCarFactory.addDecoration().docoration();
mBCarFactory.addEngine().engine();
mBCarFactory.addShell().shell();
}
}
简单的抽象工厂模式demo就写完了,类似于这种组装逻辑,抽象工厂模式还是游刃有余,但是你很容易发现,如果在增加一个车型,我们会增加一个工厂实现类,如果在增加一个部件,那么又会增加一个部件的基类以及多个部件实现类,同样的功能,抽象工厂模式会有很多类文件,这就是缺点了。
后记
抽象工厂分离接口和实现,很大程度上满足了高内聚低耦合的宗旨,产品生产也不需要你去具体实现,只需要自己寻找已有的零件,组装合成,很容易生产新产品。