设计模式2,3-工厂模式

说明一下设计模式:设计模式有适用的时候也有不适用的时候.并且不少存在过度设计的问题,这同时也是设计模式本人的意思.


在说工厂模式前,首先说明下设计模式是为了解决什么问题:

简单的来说就是:

在出了问题的时候,有什么新需求的时候,更新换代的时候...好改代码.


要怎么做到好改代码呢?

通俗的来讲:

1.最重要的一点:不要有大段重复代码,如果有就封装起来调用,这样需要改的时候改一个地方就行.
2.逻辑清晰:一个类的功能单一,这样那个功能需要变动,只需要改一个类
3.类和类之间,用接口关联.说白了,在我们实际编码的时候,要做到,除了一开始得到一个类,其余的时候都是接口,这样自己改代码的时候,只要保证初始的类和接口不变,就不会影响到其他人了.

如果文雅的来说,就是几个法则了,必须说明一点,其中开闭法则必须改为:尽量只修改一处,不修改明显是不可能的,而且意义不大,往往会增加能多的代码量,更多的系统复杂度.

再来说说工厂模式解决的问题(常见误区:工厂方法用于批量生产对象):
1.让别人用自己代码的时候好用;让自己修改的时候好改
2.类的创建复杂(参数多,过程复杂)
3.类的选择复杂(类似的类太多)


先设想一个情况:

假设我们要用到  a.jar  这个包
a.jar其中有 a interface  这个接口
a interface 有 xxx()方法 有   a1 -- a5  这5这具体实现的类
这个时候,我们有用到xxx()方法的时候,就要很小心的根据自己的情况来new  这几个class了,而且a.jar的开发人员要升级或者修改的时候也要保证这5个class的意义和构造方法不变,这样双方都很被动.

而如果用到了工厂方法,a.jar的开发者很高兴, 直接对外屏蔽了 a1--a5这5个类,改从工厂类里得到. 
这个时候再使用a.jar的时候情况就不一样了
使用者 需要使用 xxx() 方法的时候,只需要按照 工厂类的指引创建对应的对象,而a.jar开发者更新修改代码的时候,只需要保证 工厂类的 方法意义不变,接口不变就行了  里面随便折腾,  把 a1-a5,改成a6-a10 都行.

这是一种是非常契合面向对象编程的设计模式,如果没有弄明白工厂模式的作用,那么很可能是,大多数时候,你即是类的创建者,也是类的使用者,换个角度思考就清楚了.

工厂分为简单工厂,工厂方法(普通工厂)和抽象工厂,但其实都是工厂,都是为了实现上面的目标而开发的.其中普通工厂和抽象工厂分别是一种设计模式,简单工厂不在设计模式之列.

简单工厂:
一个工厂类,一个产品接口,多个不同的产品.
public static class SimpleFactory {
	public static Product getProduct(String type) {
		switch (type) {
		case "A":
			return new ProductA();
		case "B":
			return new ProductB();
		case "C":
			return new ProductC();		
		}
		return null;
	}
}
interface Product{
	void method();
}
class ProductA implements Product{
	@Override
	public void method() {
		System.out.println("ProductA");	
	}
}
class ProductB implements Product{
	@Override
	public void method() {
		System.out.println("ProductB");
	}
}
class ProductC implements Product{
	@Override
	public void method() {
		System.out.println("ProductC");	
	}
}

这样在需要获取ABC的时候,传入对应的值就行,而且直接造型为接口: 

Product a=SimpleFactory.getProduct("A")


评价:简单工厂很好的解决了上面三个问题,简单好用,修改并不复杂.缺点:要特别说明传什么值.所以适合自己写自己用,不太适合给别人用.

工厂方法:
工厂接口:与产品接口一一对应;
具体工厂:一个具体工厂对应一个具体产品;
产品接口:
具体产品:

interface IFactory{
	Product getProduct();
}
class FactoryA implements IFactory {
	@Override
	public Product getProduct() {
		return new ProductA();
	}
}
class FactoryB implements IFactory {
	@Override
	public Product getProduct() {
		return new ProductB();
	}
}
class FactoryC implements IFactory {
	@Override
	public Product getProduct() {
		return new ProductC();
	}
}
interface Product{
	void method();
}
class ProductA implements Product{
	@Override
	public void method() {
		System.out.println("ProductA");	
	}
}
class ProductB implements Product{
	@Override
	public void method() {
		System.out.println("ProductB");
	}
}
class ProductC implements Product{
	@Override
	public void method() {
		System.out.println("ProductC");	
	}
}

使用的时候: 

IFactory f=new FactoryA();f.getProduct();

评价:工厂方法,每一个具体产品,对应一个工厂.然后把工厂的选择抛给了用户.这种设计模式仅仅相当于一个中介,用于创建对象,当对象创建简单的时候毫无作用,并且凭空的增加了系统的复杂度.除非创建对象的过程真的非常复杂,不然不建议使用.


抽象工厂:
抽象工厂与普通工厂的区别在于:普通工厂面向具体产品,抽象工厂面向具体的系列.代码上的差别在于,抽象工厂接口存在多个方法,多个产品接口融合在一个工厂(普通工厂一个工厂接口对应一个)

一个工厂接口或抽象类:多个产品接口返回
多个具体的工厂类实现:
多个产品接口:
多个产品实现:

public class AbstractFactory {
	public static void main(String[] args) {
		AFactory apple=new FactoryAppleSerise();
		apple.getOpenWin().win();
		apple.getCloseWin().closeWin();
		AFactory windows=new FactoryWindowsSerise();
		windows.getOpenWin().win();
		windows.getCloseWin().closeWin();
	}
}


interface AFactory{
	OpenWinow getOpenWin();
	CloseWindow getCloseWin();
}
class FactoryAppleSerise implements AFactory{
	@Override
	public OpenWinow getOpenWin() {
		return new WinInApple();
	}
	@Override
	public CloseWindow getCloseWin() {
		return new CloseWinInApple();
	}	
}
class FactoryWindowsSerise implements AFactory{
	@Override
	public OpenWinow getOpenWin() {
		return new WinInWindows();
	}
	@Override
	public CloseWindow getCloseWin() {
		return new CloseWinInWindows();
	}	
}


interface OpenWinow{
	void win();
}
class WinInWindows implements OpenWinow{
	@Override
	public void win() {
		System.out.println("打开windows窗口");
	}
}
class WinInApple implements OpenWinow{
	@Override
	public void win() {
		System.out.println("打开Apple窗口");
	}
}
interface CloseWindow{
	void closeWin();
}
class CloseWinInWindows implements CloseWindow{
	@Override
	public void closeWin() {
		System.out.println("关闭windows窗口");
	}
}
class CloseWinInApple implements CloseWindow{
	@Override
	public void closeWin() {
		System.out.println("关闭Apple窗口");
	}
}

输出结果:

打开Apple窗口
关闭Apple窗口
打开windows窗口
关闭windows窗口

评价:为用户分开了错综复杂的产品类,避免用错,减少了类的创建.同样将选择抛给用户,但选择的余地减少了(普通工厂)有多少个产品就有多少个工厂,而这个是有多少个系列就有多少个工厂),逻辑清晰.编码的时候有明显分成系列的时候,建议使用,比如:用不同的数据库实现dao层...

结论:
工厂模式便于他人使用代码,便于修改代码.不是为了批量生成对象,根据自己的业务选取合适的工厂.

版权声明:本文为zzwwcat原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。