设计模式系列之工厂模式

7次阅读

共计 3184 个字符,预计需要花费 8 分钟才能阅读完成。

设计模式之工厂模式

工厂模式包括了简单工厂、工厂方法和抽象工厂。下面我从 java 实际应用的角度分别介绍这三种模式。

简单工厂模式

下面看下 JDBC 中获取 Connection 的代码

public class ConnectionFactory {public Connection createConnection(String dbType,String serverName,String dbName,String userName,String password) throws SQLException
    {if(dbType.equalsIgnoreCase("mysql"))
        {
            try 
            {Class.forName("com.mysql.cj.jdbc.Driver");
            } catch (ClassNotFoundException e) 
            {throw new RuntimeException(e);
            }
            String url = "jdbc:mysql://"+serverName+":3306/"+dbName
                    +"?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT";
            return DriverManager.getConnection(url,userName,password);
        }
        else if(dbType.equalsIgnoreCase("postgresql"))
        {
            try 
            {Class.forName("org.postgresql.Driver");
            } catch (ClassNotFoundException e) 
            {throw new RuntimeException(e);
            }
            String url = "jbdc:postgresql://"+serverName+":5432/"+dbName;
            return DriverManager.getConnection(url,userName,password);
        }
        else if(dbType.equalsIgnoreCase("MariaDB"))
        {
            try 
            {Class.forName("org.mariadb.jdbc.Driver");
            } catch (ClassNotFoundException e) 
            {throw new RuntimeException(e);
            }
            String url = "jdbc:mariadb://"+serverName+":3306/"+dbName;
            return DriverManager.getConnection(url,userName,password);
        }
        else
        {throw new IllegalArgumentException("未知的 dbType 参数类型");
        }
    }
}    

这段代码中就使用了简单工厂模式。我们传入不同的参数类型,工厂内部就会创建不同的对象实例,我们根本不用管工厂内部的实现逻辑是什么。
缺点:违背设计原则:对扩展开放,对修改关闭。因为假如我业务需要新增一个数据库 Connection 获取方式就得修改这部分的代码。

工厂方法模式

下面我们针对普通工厂模式的缺点进行优化。
我们可以定义一个工厂方法接口 IConnectionFactory,包含一个方法,交给子类去实现各自的 Connection 创建方法

public interface IConnectionFactory {Connection create(String serverName,String dbName,String userName,String password) throws SQLException;
}

创建 PostgreSqlConnectionFactory 工厂并实现 IConnectionFactory 接口

public class PostgreSqlConnectionFactory implements IConnectionFactory {

    @Override
    public Connection create(String serverName, String dbName, String userName, String password) throws SQLException {
        try 
        {Class.forName("org.postgresql.Driver");
        } catch (ClassNotFoundException e) 
        {throw new RuntimeException(e);
        }
        String url = "jbdc:postgresql://"+serverName+":5432/"+dbName;
        return DriverManager.getConnection(url,userName,password);
    }

}

创建 MySqlConnectionFactory 工厂并实现 IConnectionFactory 接口

public class MySqlConnectionFactory implements IConnectionFactory {

    @Override
    public Connection create(String serverName, String dbName, String userName, String password) throws SQLException {
        try {Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {throw new RuntimeException(e);
        }
        String url = "jdbc:mysql://" + serverName + ":3306/" + dbName
                + "?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT";
        return DriverManager.getConnection(url, userName, password);
    }

}

创建 MariaDBConnectionFactory 工厂并实现 IConnectionFactory 接口

public class MariaDBConnectionFactory implements IConnectionFactory {

    @Override
    public Connection create(String serverName, String dbName, String userName, String password) throws SQLException {
        try 
        {Class.forName("org.mariadb.jdbc.Driver");
        } catch (ClassNotFoundException e) 
        {throw new RuntimeException(e);
        }
        String url = "jdbc:mariadb://"+serverName+":3306/"+dbName;
        return DriverManager.getConnection(url,userName,password);
    }

}

测试方法

Connection conn = new MySqlConnectionFactory().create("127.0.0.1", "test", "root", "root");

工厂方法模式的优点:新增一种类型,只需增加一个工厂,并实现抽象工厂即可。
缺点就是调用者需要知道调用的子类对象对应的子类工厂。

抽象工厂

上述的一个工厂对应一个产品,如果一个工厂对应多个产品那就是我们的抽象工厂模式了。比如 Connection 接口就是应用了抽象工厂模式。其中的方法都是工厂方法,比如:createStatement、prepareStatement、prepareCall 等他们都有对应的实现类。

正文完
 0