GOF设计模式之旅------工厂模式

对于学完Java之后,很多人便直接进入JavaEE行列的开发或者Android的开发,但是最近看了各种书籍以及受软件体系结构课程的影响,越发觉得,GOF的23种模式是作为一个优秀程序员的基本素养,但是学习模式之后又不局限于模式之中。(正所谓:创建模式的人是大师,拘泥于模式的人永远是工匠。对于局限于模式之中,个人认为不应该在学习模式之后一味地专研这个方法我就一定得用23种模式中的一种,只有在合适的时机运用合适的技术,才是关键。)对于刚入门JavaEE行列的人往往觉得学习JavaEE看似学会了,但是一深究却又说不出个所以然,所以,就GOF的23种模式,我会持续更新,本人也是处于初学阶段,如若文件出现不合理之处,还望指点一二,在此先行谢过。

在学习设计模式之前,我们应该有以下图中的三个问题。

 

Why:目的、理念。  将一个领域中不变的东西先定义好,比如整体结构和一些主要职责(如数据库操作、事务跟踪、安全等),余下就是变化的东西了。

How:具体操作方法和措施。  设计模式贯穿一个原理:面向接口编程

What:现象、成果。   降低耦合,增强灵活性。

了解以上的Why-How-What之后,我们首先来看第一个模式:工厂模式。

工厂模式分为以下三类

1.简单工厂  

2.工厂  

3.抽象工厂

(严格来说其实是两类。从本质上来讲,抽象工厂和工厂是统一的,只不过抽象工厂是多产品系列的,而工厂是单产品系列的。其实无多大关系)

首先来了解一下第一类:简单工厂

一、简单工厂类编写步骤:
1.定制抽象产品接口,如ICar
2.定制具体产品子类,如TopCar,MidCar,LowCar
3.定制工厂类,如SimpleFactory。
简单工厂类的特点:它是一个具体的类,非接口或抽象类。其中一个重要的create()方法,
利用if...else或switch开关创建所需要的产品,并返回。
简单工厂类的方法通常是静态的,所以也被称为静态工厂。如果要防止客户端无谓地创建简单工厂示例,还可以把简单工厂的构造方法私有化。

UML模型如下图:


package com.lzw.gof.factory01;

	public interface ICar {
	
		//由于工厂模式仅关系对象的创建,为方便说明,无需定义方法
	
	}

	public class LowCar implements ICar{
	
	}

	public class MidCar implements ICar{
	
	}

	public class TopCar implements ICar{
	
	}

	public class CarSimpleFactory {
	public static final String TOPTYPE = "toptype";
	public static final String MIDTYPE = "midtype";
	public static final String LOWTYPE = "lowtype";
	public static ICar create(String mark){
		ICar obj = null;
		if(mark.equals(TOPTYPE)){
			obj = new TopCar();
		}else if(mark.equals(MIDTYPE)){
			obj = new MidCar();
		}else if(mark.equals(LOWTYPE)){
			obj = new LowCar();
		}
		return obj;
	}
}

如果此时有如下需求:

需求:如果在此基础上要增加一个超高档类型的汽车,在简单工厂模式下,需要有如下步骤:
1.新增一个产品子类,SuperCar
2.在SimpleFactory的create()方法中添加SuperCar的选择分支
改进:步骤1是必然,那么能否在不修改2的基础上进行添加SuperCar
方案:使用 工厂 来进行解决。


二、工厂类编写步骤:
1.定制抽象产品接口,如ICar
2.定制具体产品子类,如TopCar,MidCar,LowCar
3.定制抽象工厂类(或接口),如AbstractFactory。其中有一个重要的create()抽象方法
4.定制具体工厂子类,如TopFactory、MidFactory、LowFactory

优势:更有易于软件的二次开发及维护,当需求发生改变时,只需要增加、删除相应的类,而不是修改类。

UML模型如下图:

package com.lzw.gof.factory01;

	public interface ICar {
	
		//由于工厂模式仅关系对象的创建,为方便说明,无需定义方法
	
	}

	public class LowCar implements ICar{
	
	}

	public class MidCar implements ICar{
	
	}

	public class TopCar implements ICar{
	
	}

	public class SuperCar implements ICar {
	
	}
	
	public abstract class AbstractFactory {
		public abstract ICar create();
	}

	public class LowFactory extends AbstractFactory {

	@Override
	public ICar create() {
		// TODO Auto-generated method stub
		return new LowCar();
		}
	}
	
	public class MidFactory extends AbstractFactory {

	@Override
	public ICar create() {
		// TODO Auto-generated method stub
		return new MidCar();
		}
	}
	public class TopFactory extends AbstractFactory {

	@Override
	public ICar create() {
		// TODO Auto-generated method stub
		return new TopCar();
		}
	}
	public class SuperFactory extends AbstractFactory {

	@Override
	public ICar create() {
		// TODO Auto-generated method stub
		return new SuperCar();
		}
	}
}

简单工厂和工厂二者之间的区别:
工厂把简单工厂中具体的工厂类(如CarSimpleFactory)
划分成两层:抽象工厂层(AbstractFactory)和具体工厂子类层(如TopFactory)。

最后来看一下抽象工厂:

三、抽象工厂编写步骤:
1.定制抽象产品接口,如ICar,IBus
2.定制具体产品子类,如小汽车类TopCar、MidCar、LowCar,公共汽车类TopBus、MidBus、LowBus
3.定制抽象工厂类(或接口),如AbstractFactory,其中两个重要的create()抽象方法,分别返回ICar、IBus对象
4.定制具体工厂子类,如TopFactory、MidFactory、LowFactory,每个工厂重写create()方法

public interface ICar {
	
}
public interface IBus {

}
public class LowCar implements ICar{
	
}
public class MidCar implements ICar{
	
}
public class TopCar implements ICar{
	
}
public class LowBus implements IBus{

}
public class MidBus implements IBus {

}
public class TopBus implements IBus{

}
public abstract class AbstractFactory{
	public abstract ICar createCar();  //产生小汽车对象
	public abstract IBus createBus();  //产生公共汽车对象
}
public class LowFactory extends AbstractFactory {

	@Override
	public ICar createCar() {
		// TODO Auto-generated method stub
		return new LowCar();
	}

	@Override
	public IBus createBus() {
		// TODO Auto-generated method stub
		return new LowBus();
	}

}
public class MidFactory extends AbstractFactory {

	@Override
	public ICar createCar() {
		// TODO Auto-generated method stub
		return new MidCar();
	}

	@Override
	public IBus createBus() {
		// TODO Auto-generated method stub
		return new MidBus();
	}

}
public class TopFactory extends AbstractFactory {

	@Override
	public ICar createCar() {
		// TODO Auto-generated method stub
		return new TopCar();
	}

	@Override
	public IBus createBus() {
		// TODO Auto-generated method stub
		return new TopBus();
	}

}

至此,工厂模式基本上已经讲完了。下面通过一个示例再来深入理解一个工厂模式。


实战:编写读文件功能。具体功能是:
读取文本文件,包括(GBK,UTF-8,UNICODE)编码下的文本文件,要求获得全文内容;
读取图像文件,包括(BMP,JPG,GIF)文件,要求获得图像宽度、长度、每一点的RGB三基色信息

1.定义读(文本、图像)文件接口
读文本需要两个参数:文件名,文件编码格式。  由题意,读文本文件需要返回String类型
读图像需要一个参数:文件名。  由题意,读图像文件需要返回图像长、宽、RGB复合信息.  JDK提供了ImageIO,封装了对BMP,JPG,GIF等格式图像文件的读写操作
需要解决的关键问题:如何用接口来屏蔽方法参数个数,返回值类型的差异。
解决方案:定义泛型接口是解决返回值类型不同的较好方法,而屏蔽方法参数个数差异利用  "String...in" 形式即可实现
因此定义的接口如下:
public interface IRead<T>{
T read(String ... in);
}
2.定义读文本文件、图像文件具体类
3.定义抽象工厂
4.定义具体工厂

public interface IRead<T> {
	T read(String ... in );
}

/**
 * @author pc
 *	读取文本文件
 */
public class TextRead implements IRead<String> {

	@Override
	public String read(String ... in) {  //可输入0个或多个参数
		String result = null;  //结果串
		try {
			File file = new File(in[0]);   //in[0]表示文件名称
			long len = file.length();
			FileInputStream fis = new FileInputStream(in[0]);
			byte buf[] = new byte[(int) len];  //缓冲区大小等于文件长度
			fis.read(buf);   //一次读完文件
			result = new String(buf,in[1]);  //按in[1]编码方式转化成可见字符串
			fis.close();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return result;
	}
	
}
/**
 * @author pc
 *	图像基本信息文件
 */
public class ImageInfo {
	private int width;	
	private int height;
	private int r[][];	//红色分量
	private int g[][];	//绿色分量
	private int b[][];	//蓝色分量
	
	public int getWidth() {
		return width;
	}
	public void setWidth(int width) {
		this.width = width;
	}
	public int getHeight() {
		return height;
	}
	public void setHeight(int height) {
		this.height = height;
	}
	
	public int[][] getR() {
		return r;
	}
	public int[][] getG() {
		return g;
	}
	public int[][] getB() {
		return b;
	}

	public void setRGB(int rgb[]){
		r = new int[height][width];
		g = new int[height][width];
		b = new int[height][width];
		int pos = 0;
		for(int i=0; i<height; i++){
			pos = width * i;
			for(int j=0; j<width; j++){
				r[i][j] = (rgb[pos+j]&0xff0000) >> 16;
				g[i][j] = (rgb[pos+j]&0x00ff00) >> 8;
				b[i][j] = rgb[pos+j]&0x0000ff;
			}
		}
	}
	
}
/**
 * @author pc
 *	读图像文件
 */
public class ImageRead implements IRead<ImageInfo> {

	@Override
	public ImageInfo read(String... in) {
		BufferedImage bi = null;
		File file = new File(in[0]);  //in[0]表示文件名称
		try{
			bi = ImageIO.read(file);	
		}catch(IOException e){
			System.out.println(e.getMessage());
		}
		int width = bi.getWidth();
		int height = bi.getHeight();
		int rgb[] = new int[width * height];
		//将图像数据读到result缓冲区中
		bi.getRGB(0, 0, width, height, rgb, width, height);
		ImageInfo obj = new ImageInfo();  //设置图像信息
		obj.setWidth(width);
		obj.setHeight(height);
		obj.setRGB(rgb);
		return obj;
	}
	
}
public abstract class AbstractFactory {
	public abstract IRead create();
}
public class TextFactory extends AbstractFactory{

	@Override
	public IRead create() {
		return new TextRead();
	}

}
public class ImageFactory extends AbstractFactory{

	@Override
	public IRead create() {
		return new ImageRead();
	}

}
文章中若有讲解不到位或者有错误的地方,还请阅读者留言告知,先在此谢过。











1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、5资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值