您的位置:首页 > 其它

浅谈 简单工厂模式,工厂方法模式,抽象工厂模式的优点和缺点

2012-04-08 20:06 134 查看
1.简单工厂模式:
简单工厂模式的实质是由一个工厂类根据传入的参数 动态决定应该创建出哪一个产品类的实例
工厂类角色,抽象产品角色,具体产品角色

严格说这并不是一个设计模式,简单工厂没有抽象类,只有一个工厂类,这个类有个工厂方法是专门返回一个具体产品类,具体返回什么具体实例是根据传入的参数要CASE判断的

用手机生产做例子:
比如说诺基亚简单工厂用于生产手机的,传入的参数是手机型号,根据不同的型号生少不同的手机,很明显缺点就是每生产一个新型号手机就要修改工厂类,增加CASE判断,这就违背了开放-封闭原则
代码如下:
// 简单工厂类
public class SimpleFactory {

private Work work;

public Object workObject(int i) {
switch (i) {
case 1:
work = new StudentWorkImp();
break;
case 2:
work = new TeacherWorkImpl();
break;
default:
break;

}
return work;
}

}

//抽象产品接口

public interface Work {
public void doWork();
}

//具体产品类
public class StudentWorkImp implements Work {
public void doWork() {
System.out.println("学生做作业");
}
}

public class TeacherWorkImpl implements Work {
public void doWork() {
System.out.println("老师改作业");
}
}

2.工厂方法模式
定义一个用于创建对象的接口 让子类来决定创建哪一个具体类

参与角色:
抽象产品角色 具体产品角色  抽象工厂角色  具体产品工厂角色
该模式继承了简单工厂模式的优点又克服了它的缺点 但它本身也有缺点 就是每增加一个产品类的时候都需要增加一个具体产品工厂类 增加了额外的开发量

用生产手机例子:
该模式有一个生产诺基亚的抽象类,该类里有个方法是专门生产抽象产品类的,然后不同型号的手机对应一个该型号的手机工厂,比如N97factory,此类继承抽象工厂类,类方法是专门生产具体产品类的

代码如下:
//抽象产品角色
public abstract class IWork {
public void doWork(){
}
}

//具体产品角色
public class StudentWork extends IWork{
public void doWork(){
System.out.println("学生做作业");
}
}
//具体产品角色
public class TeacherWork extends IWork{
public void doWork(){
System.out.println("老师做作业");
}
}

//抽象产品工厂
public abstract class ClassFactory {
public IWork getWork(){
return null;
}
}
//具体产品工厂
public class StudentClassFactory extends ClassFactory{
public IWork getWork(){
return new StudentWork();
}
}
//具体产品工厂
public class TeacherClassFactory extends ClassFactory{
public IWork getWork() {
return new TeacherWork();
}
}

3.抽象工厂模式
该模式和与工厂方法模式很相似,也是有个参与角色,抽象产品角色,具体产品角色,抽象工厂角色,具体工厂角色,不同的是抽象工厂类里面有多个虚工厂方法
它在我们系统实际设计当中考虑的是数据库的迁移,到时候再更改数据访问层会很麻烦,因为每种数据库的语法是不一样的,我们不能保证在以后肯定不会这么做,所以要在起初设计的时候就要考虑到这点,

现在我们模仿DAO层访问数据:
//pojo
public class User{
private String name;
private int age;

//get() set()....

}

public interface UserDao(){
public void addUser(){}
public void updateUser(){}
}

public class UserDaoMS() implements UserDao{
public void addUser(){
//mysql 的语法
}
public void updateUser(){
//mysql 的语法
}

}

现在如果我们要把mysql迁移到orcale 为了不改动原有的代码要依据开放封装的原则势必会这么做
//pojo
public class User{
private String name;
private int age;

//get() set()....

}

public interface UserDao(){
public void addUser(){}
public void updateUser(){}
}

//mysql实现
public class UserDaoMS() implements UserDao{
public void addUser(){
//mysql 的语法
}
public void updateUser(){
//mysql 的语法
}

}
// orcle实现
public class UserDaoOR() implements UserDao{
public void addUser(){
//orcle 的语法
}
public void updateUser(){
//orcle 的语法
}
}

如果这样做的话,当在Service层调用DAO层的时候需要改动的地方依然很多,这样也不是很好的设计,现在我们用了工厂方法模式实现一下
//首先一个抽象工厂接口
public interface AccessFactory{
public UserDao createUserDao();
}

public class DAOFactoryMS implements AccessFactory{
public UserDao createUseDao(){
return new UserDaoMS();
}

}

public class DAOFactoryOR implements AccessFactory{
public UserDao createUseDao(){
return new UserDaoOR();
}

}

如果按照这样的设计在Service层调用DAO的时候只要调用 AccessFactory。createUserDao()就可以得到一个具体实例以访问数据了
这样设计也有一个弊端,如果这时只有一个User实体是可以这样做的,因为工厂方法模式的抽象工厂角色中只有一个虚方法是可以返回一个抽象产品实例的
如果还有别的实体如 部门,职位这个实体,所要改动的依然很多,如果我们运用了抽象工厂模式也可以解决了这个问题,但是这样设计就会太繁琐,为什么这么说呢

请看下图
之前中有一个User实体,从而对这上实本的增删改查操作,现在多了部门实体,我们就

要每增加一个实体就要多加三个类 还要更改一个抽象工厂类,两个具体工厂类
另外有很多地方都要调用 User 和部门的DAO 当在service层里的具体类里调用他们的时候都需要声明 AccessFactory factory = new MSfactory();如果有100个就会更改100次,
这样的效率是极低的,所以有一个办法可以解决所有问题那就是 两个模式的合并:简单工厂和抽象工厂
代码如下:

public class DataAccess{
private  String db = "MS"; //代表是MYSQL

public static UserDao createUserDao(){
Class<?> classType = Class.forName("UserDao"+db);
Object object  = classType.newInstance();
return (UserDao)new object();
}
}

这个原理用的JAVA的反射机制,这两个模式的合并很好解决了以上出现的问题符合了开放-封闭原则。

总结:用最简单的话来概括就是,简单工厂只有一个具体工厂类来创建一种基类的多个不同派生类,工厂方法就是有多个派生于一个基类的具体工厂类,每个具体工厂只生产一种基类的一个派生类,抽象工厂也是只有一个工厂基类,但是每个具体工厂生产多个相关基类的各一个派生类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐