设计模式——抽象工厂模式

设计模式——抽象工厂模式

@author 无忧少年

@createTime 2019/10/16

抽象工厂模式:提供一个 创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。

抽象工厂模式(Abstract Factory)结构图

在这里插入图片描述

​ 抽象工厂模式代码示例:

// 用户接口
public interface IUser {
    void Insert(User user);
    void GetUser(String id);
}

// 访问MySql的User
public class MySqlUser implements IUser {
    @Override
    public void Insert(User user) {
        System.out.println("在MySql中给User表新增一条数据");
    }

    @Override
    public void GetUser(String id) {
        System.out.println("在MySql中根据id查询User表的一条数据");

    }
}
// 访问SqlServer的User
public class SqlServerUser implements IUser {
    @Override
    public void Insert(User user) {
        System.out.println("在sql server中给User表新增一条数据");
    }

    @Override
    public void GetUser(String id) {
        System.out.println("在sql server中根据id查询User表的一条数据");
    }
}
// Department接口
public interface IDepartment {
    void insert(Department department);

    Department getDepartmentById(String id);
}
// 访问MySql的Departmen
public class MySqlDepartment implements IDepartment {
    @Override
    public void insert(Department department) {
        System.out.println("在MySql中给department表新增一条数据");
    }

    @Override
    public Department getDepartmentById(String id) {
        System.out.println("在MySql中根据id查询department表的一条数据");
        return null;
    }
}
// 访问SqlServer的Department
public class SqlserverDepartment implements IDepartment {
    @Override
    public void insert(Department department) {
        System.out.println("在sql server中给department表新增一条数据");
    }

    @Override
    public Department getDepartmentById(String id) {
        System.out.println("在sql server中根据id查询department表的一条数据");
        return null;
    }
}
// 抽象工厂接口
public interface IFactory {
    IUser CreteUser();
    IDepartment CreateDepartment();
}
// 实现IFactory接口 实例化MySqlUser和MySqlDepartment
public class MySqlFactory implements IFactory {
    @Override
    public IUser CreteUser() {
        return new MySqlUser();
    }

    @Override
    public IDepartment CreateDepartment() {
        return new MySqlDepartment();
    }
}
// 实现IFactory接口 实例化SqlServerUser和SqlServerDepartment
public class SqlServerFactory implements IFactory {
    @Override
    public IUser CreteUser() {
        return new SqlServerUser();
    }

    @Override
    public IDepartment CreateDepartment() {
        return new SqlserverDepartment();
    }
}
// 客户端代码
public class Main {
    public static void main(String[] args) {
        User user =new User();
        Department department=new Department();

        IFactory factory =new SqlServerFactory();
        IUser iu=factory.CreteUser();
        iu.Insert(user);
        iu.GetUser("1");

        IDepartment id = factory.CreateDepartment();
        id.insert(department);
        id.getDepartmentById("1");
    }
}
// 控制台输出
在sql server中给User表新增一条数据
在sql server中根据id查询User表的一条数据
在sql server中给department表新增一条数据
在sql server中根据id查询department表的一条数据

​ 这样可以做到只需要更改IFactory factory =new SqlServerFactory()IFactory factory =new MySqlFactory() 就是先了数据库访问的切换了

​ 抽象工厂模式也有缺点,当每次需要声明ProductA 1的时候都需要先声明ConcreteFactory1,然后才能创建ProductA 1的实例,或者如果说需要增加一个类,那么也是需要改动AbstractFactory、ConcreteFactory1和ConcreteFactory2三个类,这样就太糟糕了,编程是一门艺术,这样大批量的改动,明显是非常丑陋的做法,所以可以根据简单工厂模式来改进抽象工厂。

结构图

在这里插入图片描述

​ 代码示例

//简单工厂
public class DataAccess {
    private static String db="SQLSERVER";// 数据库名称,可以替换成MYSQL
//    private static String db="MYSQL";
    public static IUser CreateUser(){
        IUser result =null;
        switch (db){
            case "SQLSERVER":
                result = new SqlServerUser();
                break;
            case "MYSQL":
                result= new MySqlUser();
                break;
        }
        return result;
    }

    public static IDepartment CreateDepartment(){
        IDepartment result =null;
        switch (db){
            case "SQLSERVER":
                result = new SqlserverDepartment();
                break;
            case "MYSQL":
                result= new MySqlDepartment();
                break;
        }
        return result;
    }
}
// 客户端代码
public class Main {
    public static void main(String[] args) {
        User user = new User();
        Department department = new Department();

        IUser iu = DataAccess.CreateUser();
        iu.Insert(user);
        iu.GetUser("1");

        IDepartment id = DataAccess.CreateDepartment();
        id.insert(department);
        id.getDepartmentById("1");
    }

}
// 控制台输出
在sql server中给User表新增一条数据
在sql server中根据id查询User表的一条数据
在sql server中给department表新增一条数据
在sql server中根据id查询department表的一条数据

​ 这里使用一个简单工厂类 DataAccess替代了原先的IFactory,SqlServerFactory,SqlServerFactory三个类,改变常量db的值即可在两个数据库做切换, 客户端也没有出现Mysql或者SqlServer字样,达到了解耦的目的。现在如果还要增加一个ORACL数据库,那么需要在DataAccess的每个方法中的switch都新增一个case。

​ 可以使用反射+抽象工厂的数据访问程序

代码示例

// 使用反射技术
public class DataAccess {
    // 包路径
    private final static String AssembleName="abstractfactory";
    // 数据库名
    private final static String db="SqlServer";
//    private static String db="Mysql";
    public static IUser CreateUser(){
        IUser result =null;
        String className=AssembleName+"."+db+"User";
        try{
            Class clz = Class.forName(className);
            result = (IUser)clz.newInstance();
        }catch (Exception e){
        }
        return result;
    }

    public static IDepartment CreateDepartment(){
        IDepartment result =null;
        String className=AssembleName+"."+db+"Department";
        try{
            Class clz = Class.forName(className);
            result = (IDepartment)clz.newInstance();
        }catch (Exception e){
        }
        return result;
    }
}
// 客户端
public class Main {
    public static void main(String[] args) {
        User user = new User();
        Department department = new Department();

        IUser iu = DataAccess.CreateUser();
        iu.Insert(user);
        iu.GetUser("1");

        IDepartment id = DataAccess.CreateDepartment();
        id.insert(department);
        id.getDepartmentById("1");
    }
}

// 控制台输出
在sql server中给User表新增一条数据
在sql server中根据id查询User表的一条数据
在sql server中给department表新增一条数据
在sql server中根据id查询department表的一条数据

其中的数据库名也可以放在配置文件中进行配置, 即使用反射+配置文件实现数据访问程序,这里就不做例子了,和上述反射技术差不多。只是将数据库名提到配置文件中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值