定义: 定义一个创建对象等借口 , 让子类决定实现哪个类
其实说白了 , 也就是一组行为相似但细节不同的类 , 可以通过普通的继承来创建不同的对象 , 而工厂模式就是讲这种普通的继承更好的管理了起来
我的理解:
概括一句话就是: 抽象工厂返回抽象产品, 具体工厂生产具体产品
这里涉及到四个名词
- 抽象工厂: 所有工厂的父类
- 具体工厂: 工厂的具体实现 , 包含业务逻辑
- 抽象产品: 产品的父类 , 在工厂中被创建
- 具体产品: 产品的具体实现.
emmm 还是有点乱哈? 先上个图然后慢慢说
场景模拟
火影忍者中很多忍术都被记载在卷轴里面 , 忍者们可以通过阅读并修炼, 从而学习到忍术.
一位下忍在训练中 , 要完成一个忍术的过程是
- 回忆所学的忍术的结印顺序
- 结印
- 释放忍术
所以我们以卷轴为工厂 , 以忍术为产品来举例子 , 首先对应一下角色的关系
- 抽象工厂----- 卷轴仓库
- 具体工厂----- 具体的某一本卷轴
- 抽象产品----- 忍术(区分于体术的概念)
- 具体产品----- 具体的某种忍术
1. 编写卷轴的类(抽象工厂)
public abstract class WaterScrolls {
public abstract <T extends Ninjutsu> T readMethod(Class<T> clazz) throws ClassNotFoundException;
}
这是一本水遁的卷轴 , 卷轴中有"阅读"这个抽象方法. 这里传入的参数为字节码文件 , 在重写方法中需要使用反射 . 返回值为忍术泛型 , 也对应到上文所说的抽象工厂返回抽象产品
2.编写忍术类(抽象产品)
public abstract class Ninjutsu {
public abstract void read(); //回忆
public abstract void ready();//结印
public abstract void go();//释放
}
一个忍术需要完成的三个阶段为: 回忆, 结印 , 释放
准备好了两个工厂 ,就可以具体的实现了
3. 编写阅读忍术的类(具体工厂)
public class ReadScrolls extends WaterScrolls {
@Override
public <T extends Ninjutsu> T readMethod(Class<T> clazz) {
Ninjutsu ni = null;
try {
ni = (Ninjutsu) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) ni;
}
}
在WaterScrolls中使用到了反射 , 在这里之需要传入忍术的class文件 , 返回值为忍术类的子类 , 也就是我们刚开始说到的 具体工厂制造具体产品
4. 编写具体的忍术类(具体产品)
这里选择两个忍术 , 水遁水乱波和水遁水鲛弹(其他的结印太长了)
//水乱波类继承了忍术类
public class WaterWave extends Ninjutsu{
@Override
public void read() {
Log.e("水遁: 水乱波: ", "辰-丑-卯");
}
@Override
public void ready() {
Log.e( "ready: ","辰-丑-卯" );
}
@Override
public void go() {
Log.e("go: ","喷水" );
}
}
//水遁水鲛弹
public class WaterShark extends Ninjutsu{
@Override
public void read() {
Log.e("水遁 水鲛弹术: ","寅—丑—辰—卯—酉—辰—未 " );
}
@Override
public void ready() {
Log.e( "ready: ","寅—丑—辰—卯—酉—辰—未" );
}
@Override
public void go() {
Log.e("go: ","水鲛弹" );
}
}
使用方法
有了上面的一系列的构造 , 我们可以从卷轴类中得到忍术 , 并使用忍术 , 这里写了battle类来模拟忍着对战
public class Battle {
public void doSomeThing(){
//第一回合 , 正常的流程
Ninjutsu firstRound=new WaterWave();
firstRound.read();
firstRound.ready();
firstRound.go();
//第二回合, 下忍早已学会忍术, 直接结印
Ninjutsu secondRound=new WaterShark();
secondRound.ready();
secondRound.go();
}
}
看到这里可能有人又要问了...... 我可以直接去new一个对象 , 在对象中去初始化啊 , 为什么还要用设计模式呢? 这里的工厂模式提供了一个模板, 我们新添加的产品在继承模板的情况下可以很方便的完成修改 , 如果一个一个的new的话 , 势必会有忘掉参数的风险 , 可维护性很低; 甚至可以新建一些抽象产品来完成产品类的扩展.
所以 , 如果在面对一些复杂但是相似的对象的时候 , 你可以试试工厂模式
网友评论