工厂方法模式的定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类
样例:女娲通过八卦炉造白种人、黄种人、黑种人。
见代码:
//工厂要生产的人的接口
public interface Human{
//有两个方法
public void getColor();
public void talk();
}
//黑种人
public class BlackHuman implements Human {
@Override
public void getColor() {
System.out.println("黑种人的皮肤是黑色的");
}
@Override
public void talk() {
System.out.println("黑人会说话,一般人都听不懂");
}
}
//黑种人
public class YellowHuman implements Human {
@Override
public void getColor() {
System.out.println("黄种人的皮肤是黄色的");
}
@Override
public void talk() {
System.out.println("黄种人会说话,一般人说的都是双字节");
}
}
//白种人
public class WhiteHuman implements Human {
@Override
public void getColor() {
System.out.println("白种人的皮肤是白色的");
}
@Override
public void talk() {
System.out.println("白种人人会说话,一般说的都是单子节");
}
}
下面的代码用到了泛型
//抽象人类创建工厂,泛型限定了输入参数必须是Class类型、必须是Human的实现类
public abstract class AbstractHumanFactory {
public abstract <T extends Human> T creatHuman(Class<T> c);
}
//人类创建工厂
public class HumanFactory extends AbstractHumanFactory {
@Override
public <T extends Human> T creatHuman(Class<T> c) {
// TODO Auto-generated method stub
Human human = null;
try{
human = (Human)Class.forName(c.getName()).newInstance();
}catch(Exception e){
System.out.println("人类生产错误");
e.printStackTrace();
}
return (T)human;
}
}
ok,现在让我们想一下女娲会给八卦炉下达什么样的生产命令呢?应该是“给我生产一个黄色人种”,而不会是“给我生产一个会走、会跑、会说话、皮肤是黄色的人”,因为这样的命令增加了交流的成本,作为一个生产的管理者,只要知道生产什么就可以了,而不需要失误的具体信息。
现在女娲开始干活了
下面的代码用到了反射机制。我写的反射机制的blog被我删了…不过这个代码挺简单的,可以理解。这里的反射机制也是反射的非常重要的应用。
public class NvWa {
public static void main(String[] args) {
AbstractHumanFactory YinYanglu = new HumanFactory();
System.out.println("--造出的第一批人是白色人种");
Human whiteHuman = YinYanglu.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
System.out.println("--造出的第二批人是黑色人种");
Human blackHuman = YinYanglu.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
System.out.println("--造出的第一批人是黄色人种");
Human yellowHuman = YinYanglu.createHuman(YellowHuman.class);
yellowHuman.getColor();
yellowHuman.talk();
}
}
怎么样,是不是辣么灰常简单~
下面是工厂模式的一个比较实用、易拓展的框架,读者可以根据实际项目需要进行拓展
//抽象产品类
public abstract class Product{
public void method1(){
//业务逻辑处理
}
//抽象方法
public abstract void method2();
}
//具体的产品类
public class ConcreteProduct01 extends Product{
public void method2(){
//业务逻辑处理
}
}
----------
public class ConcreteProduct02 extends Product{
public void method2(){
//业务逻辑处理
}
}
//抽象工厂类
public abstract class Creator{
/*
*创建一个产品对象,其输入参数类型可以自行设置
*通常为String、Enum、Class等,当然也可以为空
/*
//输入参数类型是Class,用的反射机制
public abstract <T extends Product> T createProduct(Class<T> c);
/*
*为了让大家知道为什么用反射机制,这里添加一种输入类型是String的比较一下
pubic abstract <T extends Product> T creatProduct(String productname);
*/
}
//具体工厂类
public class ContreteCreator extends Creator{
public <T extends Product> T createProduct(Class<T> c){
Product product = null;
try{
product = (Product)Class.forName(c.getName()).newInstance();
}catch(Exception e){
System.out.println("产品创造失败了");
e.printStackTrance();
}
}
/*public <T extends Product> T createProduct(String productname){
Product product = null;
try{
//反射机制可以避免这些繁琐的判断。并且如果这么写,一点你有了新的产品类,还需要来修改代码,差评~
if(productname == "productname01") product = new ConcreteProduct01();
else if(productname == "productname02")product = new ConcreteProduct02();
}catch(Exception e){
System.out.println("产品创造失败了");
e.printStackTrance();
}
}
*/
}
//场景类
public class Client{
public static void main(String[] args){
Creator creator = new ConcreteCreator();
Product product = creator.createProduct(ConcreteProduct1.class);
}
}
工厂方法模式的基本代码就是这些,下面让我们来看一下它的优点
1、首先,良好的封装性,代码结构清晰。一个调用者需要一个具体的产品对象的话,只要知道这个产品的类名(或你使用的字符串)就可以了。
2、工厂方法模式的封装性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类(用反射机制是不用修改的)或拓展一个工厂类,就可以完成“拥抱变化”。
3、屏蔽产品类。产品类如何变化,只要产品接口不变就跟我们没有关系。
4、最后,工厂模式方法是典型的解耦框架。高层模块只需要知道产品的抽象类,别的不用关心,符合迪米特法则。只依赖产品类的抽象,符合依赖倒置原则。使用产品子类替换产品父类,也符合里氏替换原则。
还没有结束!
工
厂方法模式的拓展
1、缩小为简单工厂模式。如果只有一种工厂,那么我们就不需要抽象工厂了,产品类都不需要改变,同时这个唯一工厂的方法设置成static的
public class HumanFactory{
//这里是
public static <T extends Human> T createHuman(Class<T> c){
Human human = null;
try{
human = (Human)Class.forName(c.getName()).newInstance();
}catch(Exception e){
System.out.println("人类生产错误");
e.printStackTrace();
}
return (T)human;
}
}
2、升级为多个工厂类
当我们在做一个比较复杂的项目时,经常会遇到初始化一个对象很耗费精力的情况,所有的产品类都放到一个工厂方法中进行初始化,会是代码结构不清晰。例如,如果一个产品类有5个具体实现,每个实现类的初始化(不仅仅是new,还包括对对象设置初始值等)都不相同,如果写在一个工厂方法中,势必会导致该方法类巨大无比。
怎么办呢?
每一种产品都有自己的工厂,并在自己的工厂中初始化自己。意思比较简单,就不再添加代码了,自己尝试一下吧~