Java设计模式二
今天谈的是工厂模式,该模式用于封装和对对象的创建,万物皆对象,那么万物又是产品类,如一个水果厂生产三种水果罐头,我们就可以将这三种水果作为产品类,再定义一个接口用来设定对水果罐头的生成方法,在工厂类中定义一个方法可以根据我们提供给工厂的不同参数,来生成不同的产品。这样我们就可以方便后续的扩展,例如工厂又新生产另一种水果罐头,那么我们只需要添加相应的水果类,传入工厂相应的制造方法即可。下面我们通过具体的代码来理解工厂模式的实现。
标准的工厂类设计###
工厂类的定义是:定义一个用于创建对象的接口,让子类决定实例化哪个类,工厂方法使得一个类的实例化延迟到子类。我们定义一个水果类(抽象),让苹果,桔子类继承水果类。定义一个工厂(抽象),使用泛型的抽象方法,再定义一个或者多个具体的工厂继承该抽象工厂的抽象方法。生产中当调用工厂时传入想要生产的水果类(具体)即可。
package com.factor;
/**
* 抽象水果类
*/
public abstract class Fruit {
public void getClassname(){
System.out.println("我属于水果");
}
public abstract void getname();
}
package com.factor;
/**
*
* @author Administrator
* 苹果
*/
public class Apple extends Fruit{
public void getname() {
// TODO Auto-generated method stub
System.out.println("我是一个苹果");
}
}
package com.factor;
/**
*
* @author Administrator
* 桔子
*/
public class Orange extends Fruit{
public void getname() {
// TODO Auto-generated method stub
System.out.println("我是一个桔子");
}
}
/**
*
* @author Administrator
* 抽象工厂
*/
public abstract class AbstractFactory {
public abstract <T extends Fruit> T createFriut(Class<T> c);
}
/**
*
* @author Administrator
* 水果工厂
*/
public class FruitFactory extends AbstractFactory {
@Override
public <T extends Fruit> T createFriut(Class<T> c) {
// TODO Auto-generated method stub
System.out.println("开始制作");
Fruit fruit=null;
try {
fruit = (Fruit)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (T)fruit;
}
}
场景类:
public class Click {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractFactory factory = new FruitFactory();
Fruit apple = factory.createFriut(Apple.class);
apple.getClassname();
apple.getname();
}
}
运行结果
工厂方法模式拥有良好的封装性,代码结构清晰,另外对对象的创建有约束的作用如上面代码中使用界定限制工厂只能生产水果),其次工厂模式的扩展性也很优秀,如需要增加产品的生产,只添加相应的产品类,适当的修改或者增加一个工厂类即可。我们从工厂方法中也能看到迪米特法则的运用,也就是高层模块只需要知道产品的抽象类,其它的类“不关心”。也可以看出一个产品只依赖产品的抽象这也是符合依赖倒置的。
工厂模式扩展###
1.缩小为简单工厂模式
如果我们只需要一个工厂生产水果,那么我们可以把工厂抽象类中的方法放到具体工厂类中即可。
/**
*
* @author Administrator
* 水果工厂
*/
public class FruitFactory {
public static <T extends Fruit> T createFriut(Class<T> c) {
// TODO Auto-generated method stub
System.out.println("开始制作");
Fruit fruit=null;
try {
fruit = (Fruit)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return (T)fruit;
}
}
这使得我们的类变得简单,而且调用也简单了,所以称为简单工厂模式也叫做静态工厂模式。这样做也存在不符合开闭原则的缺点,不利于扩展。
2.多工厂模式
我们可以使用多个工厂来生产产品,比如有苹果工厂,有桔子工厂等。
/**
*
* @author Administrator
* 多工厂中的抽象工厂 区别: 不适用泛型 直接生成一个产品大类
*/
public abstract class MaxFaxtory {
public abstract Fruit create();
}
具体的工厂类:
/**
*
* @author Administrator
* 多工厂模式
*/
public class AppleFactory extends MaxFaxtory {
@Override
public Fruit create() {
// TODO Auto-generated method stub
return new Apple();
}
/**
*
* @author Administrator
* 所工厂模式 桔子工厂
*/
public class OracleFactory extends MaxFaxtory{
@Override
public Fruit create() {
// TODO Auto-generated method stub
return new Orange();
}
}
这样做使得各个工厂之间职责清晰,结构简单,但也是不利于扩展。我们可以使用一个协调类避免调用者与各个子工厂交流,协调类的作用是封装工厂类,对高层模块提供统一的访问接口。
3.替代单例模式
/**
*
* @author Administrator
* 单例类
*/
public class Singleton {
//不允许new
private Singleton(){
}
public void doSomething(){
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class SingletonFactory {
private static Singleton singleton;
static{
try {
Class c1=Class.forName(Singleton.class.getName());
Constructor constructor=c1.getDeclaredConstructor();
constructor.setAccessible(true);
singleton = (Singleton)constructor.newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
SingletonFactory通过反射的方法创建一个单例对象。
4.延迟初始化
一个对象被消费完毕后,并不立即释放,而是保持初始状态,等待再次被调用。
/**
*
* @author Administrator
* 延迟加载的工厂类
*/
public class ProductFactory {
private static final Map<String,Fruit> prMap = new HashMap();
public static synchronized Fruit createFruit(String type) throws Exception{
Fruit fruit = null;
if(prMap.containsKey(type)){
fruit = prMap.get(type);
}else{
if(type.equals("apple")){
fruit = new Apple();
}else{
fruit = new Orange();
}
}
return fruit;
}
}
延迟加载的框架易于扩展,可以通过判断Map中已有的对象数量来实现。通过延迟加载也降低了对象生成与销毁带来的问题。