您的位置:首页 > 编程语言 > Go语言

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

2016-09-12 17:16 363 查看
对于学完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();
}

}
文章中若有讲解不到位或者有错误的地方,还请阅读者留言告知,先在此谢过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: