工廠模式一共分爲三種,分別是:簡單工廠模式,工廠方法模式和抽象工廠模式。
先來說說簡單工廠模式,簡單工廠模式一般不在實際中是用,因爲它的擴展性不好,這裏的擴展性,是指我們可以添加新的類,而不是去更改現有的類,這樣做的好處顯而易見,如果爲了一個新需求去更改原有類的代碼,那麼就有可能引入新的bug,如果是新加一個類,這就可以非常有效地降低引入新bug的風險,因此,擴展性是非常重要的。下面是一個簡單工廠模式的例子:
- public interface Fruit{
- }
- public class Apple implements Fruit{
- }
- public class Grape implements Fruit{
- }
- public class Strawberry implements Fruit{
- }
- public class FruitGardener
- {
- public static Fruit factory(String whichFruit)
- {
- if (which.equalsIgnoreCase("apple"))
- {
- return new Apple();
- }
- else if (which.equalsIgnoreCase("strawberry"))
- {
- return new Strawberry();
- }
- else if (which.equalsIgnoreCase("grape"))
- {
- return new Grape();
- }
- else
- {
- return new null;
- }
- }
- }
上面的代碼很容易看懂,想要得到一個Apple,用Apple apple = FruitGardener.factory("apple");這句話就行了。這樣看來,上面的代碼已經實現了工廠模式,事實也的確如此,但是問題就在於先前所提到的擴展性,當我們想要這個果園能生產香蕉的時候,必須做下面兩件事情,第一,寫一個Banana類,它實現了接口Fruit,然後再更改FruitGardener,讓其能夠生產Banana,如下:
- public class Banana implements Fruit{
- }
- public class FruitGardener
- {
- public static Fruit factory(String whichFruit)
- {
- if (which.equalsIgnoreCase("apple"))
- {
- return new Apple();
- }
- else if (which.equalsIgnoreCase("strawberry"))
- {
- return new Strawberry();
- }
- else if (which.equalsIgnoreCase("grape"))
- {
- return new Grape();
- }
- else if (which.equalsIgnoreCase("banana"))
- {
- return new Banana();
- }
- else
- {
- return new null;
- }
- }
- }
這樣就違背了我們先前說的只能新加類,不能修改現有類的原則,因此,簡單工廠模式只能做一個教學演示而已。
下面是第二個,叫工廠方法模式,這個方法有效地解決了簡單工廠模式擴展性差的問題,想要進行擴展,只需要新加類就行,不需要更改原油類,下面是一個例子:
- public interface Mobile {
- }
- public class Motorola implements Mobile {
- }
- public class Nokia implements Mobile {
- }
- public interface MobileFactory {
- public Mobile produceMobile();
- }
- public class NokiaFactory implements MobileFactory {
- @Override
- public Mobile produceMobile() {
- return new Nokia();
- }
- }
- public class MotorolaFactory implements MobileFactory {
- @Override
- public Mobile produceMobile() {
- return new Motorola();
- }
- }
- public class Client {
- public static void main(String[] args){
- MobileFactory mf;
- Mobile m;
- mf = new MotorolaFactory();
- m = mf.produceMobile();
- //這時,m是Motorola的手機
- mf = new NokiaFactory();
- m = mf.produceMobile();
- //這時,m是Nokia的手機
- }
- }
如果想要生產HTC的手機,只需要新加一個HTC類,實現Mobile接口,再新加一個HTCFactory,實現MobileFactory接口就行了,新加的代碼如下:
- public class HTC implements Mobile {
- }
- public class HTCFactory implements MobileFactory {
- @Override
- public Mobile produceMobile() {
- return new HTC();
- }
- }
這樣就實現了新加一個這個工廠產的產品,但是不會更改原有類的要求,但是,這還會有問題。在工廠方法模式中,到底生產什麼,是寫進了代碼裏(我們俗稱硬代碼),假如客戶這次想要Nokia,下次又想要Motorola了怎麼辦,總不可能他提一次需求我們就改一次代碼吧,這樣顯然是不行的,因此,下面又有了抽象工廠模式。先是一個例子:
- interface Dao {
- }
- class OracleDao implements Dao {
- }
- class MySqlDao implements Dao {
- }
- abstract class DaoFactory {
- abstract Dao getDao();
- public static DaoFactory getInstance(String classname) {
- DaoFactory dao = null;
- try {
- dao = (DaoFactory) Class.forName(classname).newInstance();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return dao;
- }
- }
- class OracleFactory extends DaoFactory {
- @Override
- Dao getDao() {
- // TODO Auto-generated method stub
- return new OracleDao();
- }
- }
- class MysqlFactory extends DaoFactory {
- @Override
- public Dao getDao() {
- // TODO Auto-generated method stub
- return new MySqlDao();
- }
- }
- class Config {
- static final String FACTORYNAME = "OracleFactory";
- }
- public class Test {
- public static void main(String[] args) {
- Dao dao = null;
- dao = DaoFactory.getInstance(Config.FACTORYNAME).getDao();
- System.out.println(dao.getClass().getName());
- //打印的結果是OracleDao
- }
- }
上面的代碼中,想要生產什麼,是寫在配置文件裏的,Config這個類實際上可以寫成一個properties文件,用戶想要生產什麼,按照要求改這個文件就可以了,不需要改代碼。再回頭看看這個抽象工廠模式滿不滿足可擴展性,如果想要生產SqlServer的數據庫訪問對象(DAO,Data Access Object),需要新加一個SqlServerDao類來實現DAO接口,再新增一個SqlServerFactory實現DaoFactory,另外,需要告訴客戶現在的系統已經能夠生產SqlServer數據訪問對象了,你只需要在配置文件里加上類似static final String MYSQL = "org.abc.SqlServerFactory"; 的話(按照配置文件的格式來寫)就行了。
上面就介紹完了工廠模式,下期預告,Builder模式。