本例子背景为根据客户端不同的选择,生成不同的数据库连接

0. 无工厂代码

package nofactory;

public class NoFactory {
    private static final short MYSQL = 0;
    private static final short SQLSERVER = 1;

    public static void connect(short dbType) {
        switch (dbType) {
            case MYSQL:
                System.out.println("MySQL connected");
                break;
            case SQLSERVER:
                System.out.println("SQLServer connected");
                break;
            default:
                System.out.println("Unknown database type");
        }
    }

    public static void main(String[] args) {
        connect(MYSQL);
    }
}

这种写法的坏处在于客户端代码和产品代码(数据库)紧耦合,每次需求修改(例如添加数据库,更改数据库表现方式等等)需要对整个代码进行改动。

 

1. 使用工厂,先看如下3个固定的产品类

DataBase.java

package db;

public abstract class DataBase {
    public static final short MYSQL = 0;
    public static final short SQLSERVER = 1;
    public static final String MYSQL_CLASSNAME = "db.MySQL";
    public static final String SQLSERVER_CLASSNAME = "db.SQLServer";
    public abstract void connect();
}

MySQL.java

package db;

public class MySQL extends DataBase {
    @Override
    public void connect() {
        System.out.println("MySQL connected");
    }
}

SQLServer.java

package db;

public class SQLServer extends DataBase {
    @Override
    public void connect() {
        System.out.println("SQLServer connected");
    }
}

 

1.1 简单工厂

package simplefactory;

import db.DataBase;
import db.MySQL;
import db.SQLServer;

public class DBFactory {
    private DBFactory() {}

    public static DataBase createDataBase(short dbType) {
        switch (dbType) {
            case DataBase.MYSQL:
                return new MySQL();
            case DataBase.SQLSERVER:
                return new SQLServer();
            default:
                return null;
        }
    }
}

客户端

package simplefactory;

import db.DataBase;

public class Test {
    public static void main(String[] args) {
        DataBase db = DBFactory.createDataBase(DataBase.MYSQL);
        db.connect();
    }
}

简单工厂的好处在于将客户端和产品分离,使得要生成不同的数据库链接只需要修改客户端就可以

缺点在于产品工厂的生产全在一起(耦合),如果添加了产品需要修改switch语句,从而会影响到其他产品

 

1.2 工厂方法

DBFactory.java

package factorymethod;

import db.DataBase;

public class DBFactory {
    protected DBFactory() {}
    protected static DataBase createDB() { return null; }
}

MySQLFactory.java

package factorymethod;

import db.DataBase;
import db.MySQL;

public class MySQLFactory extends DBFactory{
    private MySQLFactory() {}

    public static DataBase createDB() {
        return new MySQL();
    }
}

SQLServerFactory.java

package factorymethod;

import db.DataBase;
import db.SQLServer;

public class SQLServerFactory extends DBFactory{
    private SQLServerFactory() {}

    public static DataBase createDB() {
        return new SQLServer();
    }
}

 

客户端

package factorymethod;

import db.DataBase;

public class Test {
    public static void main(String[] args) {
        DataBase db = SQLServerFactory.createDB();
        db.connect();
    }
}


工厂方法的目的在于消除简单工厂里的 switch , 达到添加和修改产品类的时候产品之间互相解耦,另外要特别注意工厂父类的protected的使用,他可以防止客户端直接创造父类工厂(因为一般来说客户端和工厂类不会在同一个包里)。

其实我Y就一直明白这TM漫天遍地都是用这个形式的例子来介绍工厂方法,这个例子就是个悲剧。我就问了,你Y在客户端直接new和你用这一大堆工厂有何区别,如下:

public static void main(String[] args) {
    DataBase db = new MySQL();
    db.connect();
}

这和你上面的工厂方法有何区别,还省去了一大堆的工厂

 

1.3  。。。

ABFactory.java

package abstractfactory;

import db.DataBase;

public class ABFactory {
    private ABFactory() {}

    public static DataBase createDB(String dbName) {
        try {
            return (DataBase) Class.forName(dbName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

客户端

package abstractfactory;

import db.DataBase;

public class Test {
    public static void main(String[] args) {
        DataBase db = ABFactory.createDB(DataBase.MYSQL_CLASSNAME);
        db.connect();
    }
}

 

他的优点就显而易见了,即使你怎么添加产品类和修改产品类,也不需要去修改工厂,而且和客户端彻底解耦,一般来讲我们可以将数据库的类名放在XML配置文件里,工厂方法去读取他就可以了,就像Spring的配置文件那样。

posted on 2012-11-02 02:07  ZimZz  阅读(350)  评论(0编辑  收藏  举报