工厂方法

定义:提供抽象方法或者接口,让子类或者实现类根据情况或者给定参数决定哪些类类或者方法应该被实例化或者被调用。

使用及优点:
[list]
[*]连接平行的类层次结构
[*]一个希望子类指定对象的类
[*]一个类无法预料他的子类时必须被创建
[*]通过使用共享接口来分开对象家庭
[*]该代码是需要处理的接口,而不是实现了的类
[*]对客户端隐藏具体的类
[*]工厂方法可以被参数化
[*]放回的对象可以是抽象类的也可以是具体类
[*]提供钩子给子类比直接创建对象更灵活
[*]遵守命名规则以帮助其他开发者认识代码结构
[*]相关模式:
抽象工厂: 比工厂方法高一层
模板方法: 他定义了一个算法的骨架让子类遵守或者避免子类
原型: 他通过拷贝实例创建新对象,因此他可以减少子类
单例: 他可以让返回的工厂方法唯一
[/list]

例子:为了理解这个概念,让我们一起看一些简单的例子。


interface Shape {
public void draw();
}
class Line implements Shape {
Point x, y;
Line(Point a, Point b) {
x = a;
y = b;
}
public void draw() {
//draw a line;
}
}
class Square implements Shape {
Point start;
int width, height;
Square(Point s, int w, int h) {
start = s;
width = w;
height = h;
}
public void draw() {
//draw a square;
}
}
class Circle implements Shape {
....
}

class Painting {
Point x, y;
int width, height, radius;
Painting(Point a, Point b, int w, int h, int r) {
x = a;
y = b;
width = w;
height = h;
radius = r;
}
Shape drawLine() {
return new Line(x,y);
}
Shape drawSquare() {
return new Square(x, width, height);
}
Shape drawCircle() {
return new Circle(x, radius);
}
....
}

...
Shape pic;
Painting pt;
//initializing pt
....
if (line)
pic = pt.drawLine();
if (square)
pic = pt.drawSquare();
if (circle)
pic = pt.drawCircle();


从上边的例子,你可以看到Shape中pic的类型依赖于给定的条件,可能是一条线,一个矩形或者一个圆形。

我们需要更多的构造器,从而根据不同的参数来实例化更多需要的对象。这是另外一种工厂设计方法。

class Painting {
...
Painting(Point a, Point b) {
new Line(a, b); //draw a line
}
Painting(Point a, int w, int h) {
new Square(a, w, h); //draw a square
}
Painting(Point a, int r){
new Circle(a, r); //draw a circle
}
...
}

你需要一些方法来完成绘画工作,这就是所谓的工厂方法模式。


class Painting {
...
Painting(Point a, Point b) {
draw(a, b); //draw a line
}
Painting(Point a, int w, int h) {
draw(a, w, h); //draw a square
}
Painting(Point a, int r){
draw(a, r); //draw a circle
}
...
}



上边draw()被重载。

这里有一个很流行的工厂设计模式的例子,例如,你有许多不同位置的数据库,基于数据库的程序是一样的,用户仅仅需要选择本地或者远程模式,这样你就需要将程序设计成工厂模式。当用户选择本地模式,你需要实例化工作在本地数据库的实例,如果选择远程数据库,你就需要创建可能做更多事情的远程实例。

interface DatabaseService {
public DataInfo getDataInfo() throws Exception;
public FieldInfo getFieldInfo() throws Exception;
public void write(FieldInfo fi) throws Exception;
public void modify(FieldInfo fi) throws Exception;
public void delete(FieldInfo fi) throws Exception;
//...
}
class Data implements DatabaseService {

public Data(String fileName) {...};
public Data(URL url, String fileName) {....};
public DataInfo getDataInfo() throws Exception {...};
public FieldInfo getFieldInfo() throws Exception {...};
public void write(FieldInfo fi) throws Exception {...};
public void modify(FieldInfo fi) throws Exception {...};
public void delete(FieldInfo fi) throws Exception {...};
//....
}
class DataManager{
Data data = null;
...
if (local) {
data = new Data(localFile);
...
}
if (remote){
data = new Data(connectRemote, databaseFile);
...
}
data.write(someInfo);
data.modify(someInfo);
....
}



为了说明如何使用类层次实现工厂模式,给出一个实际例子。一个公司有一个需要需要显示来自文本文件的测试结果,可是最近公司购进一台新机器,它产生二进制数据文件,其他类似产生其他格式数据文件的机器也在不断购进,那怎样处理这种改变那?因为站点仅仅需要显示数据,所以我们的工作就是提供给站点需要的数据格式。下边是一个解决方案,使用接口类型来汇集不同数据文件格式,下边是一种实现骨架。

//Let's say the interface is Display
interface Display {

//load a file
public void load(String fileName);

//parse the file and make a consistent data type
public void formatConsistency();

}

//deal with plain text file
class CSVFile implements Display{

public void load(String textfile) {
System.out.println("load from a txt file");
}
public void formatConsistency() {
System.out.println("txt file format changed");
}
}

//deal with XML format file
class XMLFile implements Display {

public void load(String xmlfile) {
System.out.println("load from an xml file");
}
public void formatConsistency() {
System.out.println("xml file format changed");
}
}

//deal with binary format file
class DBFile implements Display {

public void load(String dbfile) {
System.out.println("load from a db file");
}
public void formatConsistency() {
System.out.println("db file format changed");
}
}

//Test the functionality
class TestFactory {

public static void main(String[] args) {
Display display = null;

//use a command line data as a trigger
if (args[0].equals("1"))
display = new CSVFile();
else if (args[0].equals("2"))
display = new XMLFile();
else if (args[0].equals("3"))
display = new DBFile();
else
System.exit(1);

//converging code follows
display.load("");
display.formatConsistency();
}
}


将来,公司可能会添加更多的不同格式的数据文件,不过咱们的程序就只需要按照规则添加一个新类,这种设计节省了很多代码并且易于维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值