java设计模式--工厂方法模式 & 抽象工厂模式

工厂方法模式:

定义一个用于创建对象的接口, 让子类决定实例化哪一个类。 工厂方法使一个类的实例化延迟到其子类。 
角色:
Product  抽象产品,负责定义产品的共性,实现对事物抽象的定义
Creator  抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂完成
ConcreteCreator   具体实现工厂

总结一下模板代码:

/**
* 产品抽象
*/
public interface Product {
	void method();
}

/**
 * 具体产品
 */
public class ConcreteProduct1 implements Product {
    @Override
    public void method() {
        //具体产品方法
    }
}

/**
 * 抽象工厂类
 * 
 */
public interface Creator {

    /*
     * 创建一个产品对象, 其输入参数类型可以自行设置
     * 通常为String、 Enum、 Class等, 当然也可以为空。
     */
     <T extends Product> T createProduct(Class<T> c);

}

/**
 * 抽象工厂实现
 */
public class ConcreteCreator implements Creator {
    @Override
    public <T extends Product> T createProduct(Class<T> c) {
        Product product=null;
        try {
            product = (Product)Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            //异常处理
        }
        return (T)product;
    }
}

//测试代码:
public static void main(String[] args) {
	//这时要new,也可以是个静态方法。这样抽象工厂就是一个工厂类了
	Creator creator  = new ConcreteCreator();
	ConcreteProduct1 noticeProduct = creator.createProduct(ConcreteProduct1.class);
	noticeProduct.method();
}
实际中往里面套就可以了,产品也可能是抽象类,也可能是一个具体的类(万物皆对象嘛)等等可以根据自己的需要修改。

优点:
上层不用关心具体的产品是怎么实现的,只要知道用那一种产品就行。
调用者不需要知道产品如何实现。

有新的产品了,只要产品接口不变,那么所有的上层调用都不用变。唯一要变的可能就是具体工厂的实现(模板代码中,都不需要修改)。

工厂方法模式的扩展:
1、 模板代码中。只需要一个工厂 ConcreteCreator 实例,所以就没有必要把它new出来,创建对象方法使用静态方法就可以。
2、每一个产品有一个产品工厂。适用于产品比较多,每个产品的初始化方法都不相同(不仅仅是new),如果写在一个产品工厂中那么此工厂可能会比较大(方法代码多)。为了结构清晰,为每一个产品创建一个工厂类,让调用者自己去选择使用那一个工厂。
3、替代单例模式。示例代码:

	/**
	* 单例
	**/
	public class Singleton {
        //不允许通过new产生一个对象
        private Singleton() {}
        public void doSomething() {
            //业务处理
        }
    }

	/**
	* 单例工厂
	**/
    public class SingletonFactory {
        private static Singleton singleton;
		//使用静态块来创建单例对象
        static {
            try {
                Class cl = Class.forName(Singleton.class.getName());
                //获得无参构造
                Constructor constructor = cl.getDeclaredConstructor();
                //设置无参构造是可访问的
                constructor.setAccessible(true);
                //产生一个实例对象
                singleton = (Singleton) constructor.newInstance();
            } catch (Exception e) {
                //异常处理
            }
        }
        public static Singleton getSingleton() {
            return singleton;
        }
    }
4、延迟初始化。一个对象被消费完毕后, 并不立刻释放, 工厂类保持其初始状态, 等待再次被使用。 延迟初始化是工厂方法模式的一个扩展应用。
示例代码(工厂方法改写):
//容纳已经创建的对象
    private static Map<Class,Product> map =  new HashMap<>(16);

    //工厂方法
    public static synchronized <T extends Product> T create(Class<T> c) {
        Product product=null;

        if(map.containsKey(c)){
            //如果map 中已存在创建的对象直接返回
            return (T)map.get(c);
        }
        try {
            product = (Product)Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            //异常处理
        }
        return (T)product;
    }
上面都是模板代码,一切皆可扩展。工厂方法模式在项目中用的比较多,多思考如何使用,而且很容易与其它模式混合使用。






抽象工厂模式
工厂方法模式就是单独生产某一个单独具体的产品,产品之间联系。在实际的工厂中,分为很多车间,每个车间又分为多个生产线,分别生产不同的产品,生产完毕就可以在系统外组装,各个车间和生产线的职责非常明确,在车间内各个生产出来的产品可以有耦合关系,生产的时候在一个车间内协调好。这就是抽象工厂模式。

定义:
为创建一组相关或相互依赖的对象提供一个接口, 而且无须指定它们的具体类。
抽象工厂模式是工厂方法模式的升级版本, 在有多个业务品种、 业务分类时, 通过抽象工厂模式产生需要的对象是一种非常好的解决方式。 比如:生产车辆的左侧车门和右侧车门,这两个应该是数量相等的(产品之间的约束),叫做产品族。每种车型车门都是不一样的,这是产品等级结构约束。

示例:生产车门,一辆车有左侧门和右门。UML 图如下:


注:左侧门和右侧门是两个产品族, LeftDoor  BenzLeftDoor  BMWLeftDoor 为同一个产品等级,RightDoor  BenzRightDoor  BMWRightDoor  为同一个产品等级。

代码:

Door类及其子类

/**
 * 车门抽象类
 */
public abstract class Door {

    public void open(){
        System.out.println("open door");
    }
    public void close(){
        System.out.println("close door");
    }
    /**
     * 车门类型,左侧门还是右侧门
     */
    public abstract void type();
    /**
     * 子类实现
     */
    public abstract void other();

}
/**
 * 左侧门
 */
public abstract class LeftDoor extends Door{

    @Override
    public void type() {
        System.out.println("这是左侧门");
    }
}
/**
 * 右侧门
 */
public abstract class RightDoor extends Door{
    @Override
    public void type() {
        System.out.println("这是右侧门");
    }
}
/**
 * Benz 左侧门
 */
public class BenzLeftDoor extends LeftDoor {
    @Override
    public void other() {
        System.out.println("BenzLeftDoor");
    }
}
/**
 * Benz 左侧门
 */
public class BenzRightDoor extends RightDoor {
    @Override
    public void other() {
        System.out.println("BenzRightDoor");
    }
}
/**
 * BMW  车辆左侧门
 */
public class BMWLeftDoor extends LeftDoor {
    @Override
    public void other() {
        System.out.println("BMWLeftDoor 改成黑色");
    }
}
/**
 * BMW  车辆右侧门
 */
public class BMWRightDoor extends RightDoor {

    @Override
    public void other() {
        System.out.println("BMWLeftDoor 改成白色");
    }
}

工厂类

/**
 * 抽象车门创建者
 */
public abstract class AbstractDoorCreator {
    /**
     * 生产左侧门
     * @return
     */
    public abstract LeftDoor createLeftDoor();

    /**
     * 生产右侧门
     * @return
     */
    public abstract RightDoor createRightDoor();
}
/**
 * bmw 车门创建者
 */
public class BMWDoorCreator extends AbstractDoorCreator {
    @Override
    public LeftDoor createLeftDoor() {
        return new BMWLeftDoor();
    }

    @Override
    public RightDoor createRightDoor() {
        return new BMWRightDoor();
    }
}

/**
 * benz 车门创建者
 */
public class BenzDoorCreator extends AbstractDoorCreator {
    @Override
    public LeftDoor createLeftDoor() {
        return new BenzLeftDoor();
    }

    @Override
    public RightDoor createRightDoor() {
        return new BenzRightDoor();
    }
}

测试代码:

public static void main(String[] args) {
	//创建 BenzDoorCreator 工厂,生产 benz 的车门
	BenzDoorCreator benzDoorCreator = new BenzDoorCreator();
	LeftDoor benzLeftDoor = benzDoorCreator.createLeftDoor();
	RightDoor benzRightDoor = benzDoorCreator.createRightDoor();

	//创建 BMWDoorCreator 工厂,生产BWM 的车门
	BMWDoorCreator bmwDoorCreator = new BMWDoorCreator();
	LeftDoor bmwLeftDoor = bmwDoorCreator.createLeftDoor();
	RightDoor bmwRightDoor = bmwDoorCreator.createRightDoor();

	//生产完毕,可以在这里做想做的事情
}
优点:
封装性,调用者只要关心接口(抽象类)就行,只要知道具体的工厂,就能生产出想要的产品。
产品内部的约束不公开,由工厂内部实现比如生产一个左侧门就要对应一个右侧门。
缺点:
产品族扩展困难,比如要加一个天窗门,那么修改的类就多了,工厂接口都需要修改。比如:新增了一个天窗的门,那么 AbstractDoorCreator 抽象类就要加一个生产天窗门的方法,整个代码都需要修改。
注意是产品族扩展困难不是产品等级,增加一个产品等级只要新增一个产品工厂就可以了。比如新增了一个大众的车门,那么新增一个大众的车门工厂就行。

使用场景:
    一个对象族(或者一组没有关系的对象),都有相同的约束条件。如:一个文本编辑器和一个图片编辑器,两者没有关系,但是都要在windows系统和linux系统上使用,那么它们就有了同一个约束条件:操作系统。所以就可能使用抽象工厂模式,生产不同操作系统下的编辑器和图片处理器。

注:以上为模板代码,按照自己的项目可以修改。比如:车门工厂定义为 生产左侧门工厂和右侧门工厂,然后工厂类就是专用生产左侧门和右侧门的工厂类。



猜你喜欢

转载自blog.csdn.net/convict_eva/article/details/80940849