论坛首页 Java企业应用论坛

工厂方法模式应该是这样的

浏览 17775 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (4) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-08-21  
   在网上看到工厂方法的模式讲解,作者们都有意无意的跟简单工厂模式联系在一起,我认为这本身似乎就是个错误。我觉得这个模式更像是外观模式的一个变形。
首先来讲简单工厂模式。如一个接口A, 实现类有A1,A2,A3.
在客户端上调用 A a=new A1(); 很多人觉得这样不好,因为这样就把接口跟具体的实现给耦合了。好吧,我也觉得不好,但是我先不会换成简单工厂,而是会这样:
A a=null;
if(type==1){
a=new A1();
}else if(type==2){
a=new A2();
}else if(type==3){
a=new A3();
} ;

但是上面的代码还是不好,因为可能调用这个if else判断的客户端不只有这里,其他的地方也要进行这样的判断,而且判断的逻辑是一样的。于是要考虑封装,自然而然的就要用简单工厂了。 其本质应该是
对A接口的实现类的选择的逻辑的封装
但是工厂方法模式:定义一个抽象的工厂方法,在子类中实现具体应该生成哪个A的接口。看上去确实生成A接口的选择被延时到子类。但是在客户端上调用还是有个很大的问题:谁来选择具体工厂方法模式中的工厂? 简单工厂模式是把这个逻辑封装了的,到了工厂方法模式这个选择是由客户端自己来选择的:
AmethodFactory am=new A1methodFactory();//对应生成对象A1的工厂

下面我们来看看工厂方法模式是如何手jian的。

其实
A a=new A1();

这段代码已经很面向接口编程了。因为后面的操作都是用接口A的引用a进行具体的操作的。
我就是不知道选择new 哪个A的具体实现才用工厂方法模式的。结果工厂方法模式让我这么办
AmethodFactory am=new A1methodFactory();
//我怎么知道选A1methodFactory 而不是选A2methodFactory的?
A a=am.createA();//当然标准的做法这个方法是不要对外暴露的

这样的实现根本就没有起到把我将选择的逻辑封装起来,我还要多加个工厂AmethodFactory  还得在上面加实现
用来“开闭”我需求的增加。  我认为为了开闭的话,下面的代码就够了
A a=new A1();
反正客户端已经知道怎么选了,换个实现就行了嘛
A a=new A2();
A a=new A3();
A a=new A3();
要加需求就在加个类实现A接口,在这里在new之就行了,非常的开闭了。似乎是没有必要弄什么工厂方法模式的。

但是工厂模式存在也是有他的原因的,不过不能按简单工厂的思路想,不妨按外观模式的思路想想。
客户端需要一个A的实现完成一定的功能,如
A a=new A1();
a.test(1);
a.test2("soft");
但是客户端其实不是需要a, 他需要的是个整体,是
a.test(1);
a.test2("soft");

于是需要外观模式封装之。。。
class Facade{
public void face(int i,String soft){
a.test(i);
a.test2(soft);
}

}

face方法里面的逻辑一般上是固定的。 但是问题是
face方法依赖的a是个接口,不是实现类。自然而然的需要加入所谓的工厂方法,
于是有:

class Facade{

public abstract create();
public void face(int i,String soft){//关键是这个方法的逻辑比较固定,这时候用继承的方式更好
//继承的目的其实主要是这个方法在子类里面不用写了
A a=create();
a.test(i);
a.test2(soft);
}

}


这个Facade就变成了一个工厂方法了。 所以很多设计模式在讲到
工厂方法模式的时候会说 里面的create方法最好不给外面调用的。因为其实客户端不是需要对象
A,是需要完成特定的功能,这里是face方法(他才是客户端真正需要的),只是这些功能实现又依赖A罢了。
工厂模式跟简单工厂设计理念是不同的,他没有将选择的逻辑封装,而更像是个外观模式的变体。
其实像下面的这种需求,根本就不需要使用工厂方法模式的:
A a=new A1();
a.test();// 客户端就只调这么一个方法,没有其他更复杂的逻辑了
//如果手不jian实在不需要在搞个工厂方法模式出来。



大家觉得如何?
   发表时间:2011-08-21  
我表示看不懂
0 请登录后投票
   发表时间:2011-08-21  
//Context是Android里的,该方法用来创建view
public static <T extends BaseUnit> T createUnit(Class<T> cls,Context context) {
		BaseUnit bu = null;
		try {
			bu = (BaseUnit)Class.forName(cls.getName()).getConstructor(Context.class).newInstance(context);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return (T)bu;
	}

我很懒,一般都这么用
0 请登录后投票
   发表时间:2011-08-22  
请教一下
public class buildhouse(){  //根据不同的参数类型
...
public gethouse(args){
switch(args.type){
case "red":new redhouse(args).getHouse(); break;
                        case "blue":new bluehouse(args).getHouse();break;
}

}
...
}

public interface house(){
void setcolor(args);
        void setwin(args);
void setdoor(args);
        String getHouse();
}

public class redhouse implements house{
void setcolor(args){color = args.color;}
void setwin(args){ winnumber = args.winnum; }
        void setdoor(args) { door = 1;
                             door.setColor("black");
                             door.setclock(1);
}
        String getHouse(args){
this.setcolor(args);
this.setwin(args);
this.setdoor(args);
};
}


public class bluehouse implements house{
void setcolor(args){color = args.color;}
void setwin(args){ winnumber = args.winnum; }
        void setdoor(args) { door = 2;
                             door.setColor("yellow");
                             door.setclock(1);
}
        String getHouse(args){
this.setcolor(args);
this.setwin(args);
this.setdoor(args);
};
}


如果需要增加新类型的房子,需要做的事情:
1,增加一个新的类
2,修buildhouse()的调用

如果buildhouse()需要增加新的方法,需要做的事情:
1,在buildhouse()中增加方法
2,修改所有的子类

问题:
class redhouse与class bluehouse中的方法,setcolor,setwin内容都是一样的,这样算代码重复吗?

第二种方式

public class buildhouse(){
...
public gethouse(args){
color = args.color;
winnumber = args.winnum;
        if(args.type=="red") {
door = 1;
                        door.setColor("black");
}
if(args.type=="blue"){
     door = 2;
                             door.setColor("yellow");
                           
}
door.setclock(1);

}
...
}

如果需要增加新类型的房子,需要做的事情:
需要修改gethouse的方法gethouse

问题:
每次需要修改代码的时候,都要修改gethouse.如果某些参数类型是不同的处理,又需要重新修改buildhouse.
如:

public class buildhouse(){
...
public gethouse(args){
color = args.color;
winnumber = args.winnum;
        if(args.type=="red") {
door = 1;
                        door.setColor("black");
}
if(args.type=="blue"){
     door = 2;
                             door.setColor("yellow");
                           
}
if(args.type=="green"){   //新增加的类型的处理与原来的不同
door.setclock(3);
}else{
door.setclock(1);
}
}
...
}


两种方式相比,哪种比较好?原理是什么
0 请登录后投票
   发表时间:2011-08-22  
我觉得楼主钻研的太细了。
工厂方法,外观模式从目的上来说,是完全不同的,没有必要放在一起讨论。

设计模式中,功能相近或者结构相似的模式有很多,不用像答题一样,花费大量时间,把各个细微之处都抠得这么仔细。
0 请登录后投票
   发表时间:2011-08-22  
看不懂……
0 请登录后投票
   发表时间:2011-08-22  
工厂方法模式最简单的说法就是:用一维的工厂族对应二维的产品族
0 请登录后投票
   发表时间:2011-08-22  
我也表示看不懂
0 请登录后投票
   发表时间:2011-08-22  
我硬是没看懂!
0 请登录后投票
   发表时间:2011-08-22  
最应该关心的应该是某个模式是用于在什么环境下解决什么问题、怎么解决问题,以及为什么要这样解决问题的。很多文章太表面化、形式化,看了都懂,就是跟实际应用联系不上,过后全忘。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics