设计模式(二)--工厂模式(简单工厂)

为什么要有工厂模式?

       我们在学习一个东西之前,应该要先了解下他为什么出现,他解决了什么问题。这样才可以带着思考的高效学习。
       以数据库为例,我们知道常见的关系型数据库有mysql、sqlserver、oracle等,每种数据库连接实例的创建都是复杂且易错麻烦的。如果将这些连接实例交给用户来创建,是十分不合适的。我们就希望有一个类帮我负责这些不同数据库实例的创建。我们只需要告诉它我们需要哪个数据库实例,以及一些参数(数据库名称,密码等),它来创建好然后提供给我们。这样不但可以减少代码冗余,也可以降低代码的耦合度。

简单工厂

以刚刚数据库为例子,我们尝试写一个简单的工厂类。那我们首先需要先提供下三种数据库连接类(真正的连接是很复杂的,这里简单写)。

第一步:先写个数据库连接的抽象类(水平有限,先这样写)。

假设有prepare()和finish()两个方法,他们的作用就是完成复杂的对象创建工作,由工厂对象进行调用,所以将他们访问级别设置为默认(我将工厂类和数据库类放在了一个包下)。

query()方法假设是数据库可以进行的操作,工厂创建完实例后提供给用户使用的,所以是public的。

getDatabaseName()方法留给子类重写。

package study.factory.simple;

/**
 * @author 阿呆的小鸡仔
 */
public abstract class Database {
    /**
     * 连接用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 端口
     */
    private Integer port;

    Database(String username, String password, Integer port) {
        this.username = username;
        this.password = password;
        this.port = port;
    }

    /**
     * 设置数据库名称
     * @return 数据库的名称
     */
    protected abstract String getDatabaseName();

    /**
     * 创建数据库连接实例需要的操作,每种数据库应该都是不一样的
     */
     void prepare(){
        System.out.println("开始准备进行 "+this.getDatabaseName()+" 需要的初始化步骤");
        System.out.println("验证密码 "+this.password+" 是否正确......");
        System.out.println("各种初始化操作=======");
    }

    /**
     * 创建连接完成时的操作
     */
    void finish(){
        System.out.println("用户:"+this.username
                +" \n已经成功连接至"+this.getDatabaseName()
                +"\n端口:"+this.port
        );
    }

    /**
     * 假设这个是实例的功能,可以用来执行查询语句
     * @param query 查询语句
     */
    public abstract void query(String query);

}
第二步:写一下Mysql类和SqlServer类
package study.factory.simple;

/**
 * @author 阿呆的小鸡仔
 */
public class Mysql extends Database {


    Mysql(String username, String password, Integer port) {
        super(username, password, port);
    }

    @Override
    public String getDatabaseName() {
        return "MySQL数据库";
    }

    @Override
    public void query(String query) {
        System.out.println(getDatabaseName()+"执行了:"+query);
    }

}

这里重写下SqlServer的prepare(),区别下mysql与sqlserver的准备工作是不一样。

package study.factory.simple;

/**
 * @author 阿呆的小鸡仔
 */
public class SqlServer extends Database {

    SqlServer(String username, String password, Integer port) {
        super(username, password, port);
    }

    @Override
    public String getDatabaseName() {
        return "SQLServer数据库";
    }

    @Override
     void prepare() {
        System.out.println(getDatabaseName()+" 初始化完成");
    }

    @Override
    public void query(String query) {
        System.out.println(getDatabaseName()+"执行了:"+query);
    }
}
第三步:写我们的简单工厂类
package study.factory.simple;

/**
 * @author 阿呆的小鸡仔
 */
public class SimpleFactory {
	/**
     * 用来创建我们所需要的数据库实例
     * @param type 数据库类型
     * @param username 用户名
     * @param password 密码
     * @param port 端口
     * @return 数据库实例
     */
    public static Database createDatabase(DatabaseType type,String username,String password,Integer port){
        Database database=null;
        if(DatabaseType.MYSQL==type){
        	/*现实中可能是十分复杂的*/
            database=new Mysql(username,password,port);
            database.prepare();
            database.finish();
        }
        if(DatabaseType.SQLSERVER==type){
            database=new SqlServer(username,password,port);
            database.prepare();
            database.finish();
        }
        return database;
    }


    public enum DatabaseType{
        /**
         * mysql
         */
        MYSQL,
        /**
         * sqlserver
         */
        SQLSERVER;
    }
}

第四步:写个测试类,试试使用我们的工厂类来创建对象。
/**
 * @author 阿呆的小鸡仔
 */
public class Main {
    public static void main(String[] args) {
        Database mysql = SimpleFactory.createDatabase(SimpleFactory.DatabaseType.MYSQL, "zjj", "123456", 80);
        mysql.query("select * from user");
        mysql=SimpleFactory.createDatabase(SimpleFactory.DatabaseType.SQLSERVER,"zjj", "123456", 80);
        mysql.query("select * from role");
    }
}
运行结果:程序是正常运行的,不会有影响

在这里插入图片描述

之前我们把准备工作的prepare()和finish()方法设置为了包私密,所以这里用户是无法调用,避免了用户自己创建数据库类而做导致一系列不必要的错误。

在这里插入图片描述

大致了解了简单工厂,现在分析下他的优缺点:

优点:解耦
缺点:当我们需要新增一个Oracle数据库类,我们就需要在工厂类上新增代码,这样就违反了开闭原则(开闭原则希望我们扩展项目时,只新增类,而不修改原有的类,修改原有的类可能会导致原有系统出错,不方便维护)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值