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

1)最基本的数据访问程序

用户类

/**
 * 用户类
 */
public class User {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

SqlServerUser类

用于操作用户表,假设只有“新增用户”和“得到用户”方法,其余方法以及具体的SQL语句省略。

public class SqlServerUser {
    public void insert(User user) {
        System.out.println("在SQL Server中给User表增加一条记录");
    }
    public User getUser(int id) {
        System.out.println("在SQL Server中根据ID得到User表一条记录");
        return null;
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        User user = new User();
        // 与SQL Server耦合
        SqlServerUser sqlServerUser = new SqlServerUser();
        // 插入用户
        sqlServerUser.insert(user);
        // 得到ID=1的用户
        sqlServerUser.getUser(1);
    }
}

这里之所以不能换数据库,原因在于 SqlServerUser sqlServerUser = new SqlServerUser();使得sqlServerUser这个对象被框死在SQL Server上了。如果这里是多态的,在执行时就不用考虑是哪个数据库了。所以应该用工厂方法模式封装new SqlServerUser()造成的变化。工厂方法模式是定义一个用于创建对象的接口,让子类决定实例化哪一个类。

2)使用工厂方法模式改进

在这里插入图片描述

工厂体系

/**
 * 定义一个创建访问User表对象的抽象的工厂接口
 */
public interface IFactory {
    IUser createUser();
}
// Access
public class AccessFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new AccessUser();
    }
}
// Sql Server
public class SqlServerFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new SqlServerUser();
    }
}

产品体系

User
public interface IUser {
    void insert(User user);
    User getUser(int id);
}
public class AccessUser implements IUser {
    public void insert(User user) {
        System.out.println("在Access中给User表增加一条记录");
    }
    public User getUser(int id) {
        System.out.println("在Access中根据ID得到User表一条记录");
        return null;
    }
}
public class SqlServerUser implements IUser {
    public void insert(User user) {
        System.out.println("在SQL Server中给User表增加一条记录");
    }
    public User getUser(int id) {
        System.out.println("在SQL Server中根据ID得到User表一条记录");
        return null;
    }
}
/**
 * 用户类
 */
public class User {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

客户端

public class Client {
    public static void main(String[] args) {
        User user = new User();
        // 若要改成Access数据库,只需要将本句改成IFactory factory = new AccessFactory();
        IFactory factory = new SqlServerFactory();
        IUser iUser = factory.createUser();
        iUser.insert(user);
        iUser.getUser(1);
    }
}

在这里插入图片描述

3)使用抽象工厂模式改进

如果要增加Department表呢?
抽象工厂模式一个工厂可以创建多个产品,工厂方法模式一个工厂创建一个产品。它们都可以有多个工厂,抽象工厂模式是工厂方法模式的进一步扩展。
在这里插入图片描述

工厂体系

/**
 * 定义一个创建访问Department表对象的抽象的工厂接口
 */
public interface IFactory {
    IUser createUser();

    // 增加的接口方法
    IDepartment createDepartment();
}
public class AccessFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new AccessUser();
    }
    // 增加了SqlserverDepartment工厂
    @Override
    public IDepartment createDepartment() {
        return new AccessDepartment();
    }
}
public class SqlServerFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new SqlServerUser();
    }
    // 增加了SqlServerDepartment工厂
    @Override
    public IDepartment createDepartment() {
        return new SqlServerDepartment();
    }
}

产品体系

User
public interface IUser {
    void insert(User user);
    User getUser(int id);
}
public class AccessUser implements IUser{
    public void insert(User user) {
        System.out.println("在Access中给User表增加一条记录");
    }
    public User getUser(int id) {
        System.out.println("在Access中根据ID得到User表一条记录");
        return null;
    }
}
public class SqlServerUser implements IUser{
    public void insert(User user) {
        System.out.println("在SQL Server中给User表增加一条记录");
    }
    public User getUser(int id) {
        System.out.println("在SQL Server中根据ID得到User表一条记录");
        return null;
    }
}
Department
/**
 * IDepartment接口,用于客户端访问,接触与具体数据库访问的耦合
 */
public interface IDepartment {
    void insert(Department department);
    Department getDepartment(int id);
}
public class Department {
}
public class AccessDepartment implements IDepartment{
    public void insert(Department user) {
        System.out.println("在Access中给Department表增加一条记录");
    }
    @Override
    public Department getDepartment(int id) {
        System.out.println("在Access中根据ID得到Department表一条记录");
        return null;
    }
}
public class SqlServerDepartment implements IDepartment {

    @Override
    public void insert(Department department) {
        System.out.println("在SQL Server中给Department表增加一条记录");
    }

    @Override
    public Department getDepartment(int id) {
        System.out.println("在SQL Server中根据ID得到Department表一条记录");
        return null;
    }

}

客户端

public class Client {
    public static void main(String[] args) {
        User user = new User();
        Department department = new Department();

//        IFactory factory = new SqlServerFactory();
        IFactory factory = new AccessFactory();

        // 则此时已于具体的数据库访问解除了依赖
        IUser iUser = factory.createUser();
        iUser.insert(user);
        iUser.getUser(1);

        IDepartment iDepartment = factory.createDepartment();
        iDepartment.insert(department);
        iDepartment.getDepartment(1);
    }
}

在这里插入图片描述

4)抽象工厂模式

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
在这里插入图片描述

抽象工厂接口

抽象工厂接口,它里面应该包含所有的产品创建的抽象方法。
AbstractFactory是一个抽象工厂接口,它里面应该包含所有的产品创建的抽象方法。

public interface AbstractFactory {
    public AbstractProductA createProductA();

    public AbstractProductB createProductB();
}

具体的工厂

具体的工厂,创建具有特定实现的产品对象。

public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return null;
    }
    @Override
    public AbstractProductB createProductB() {
        return null;
    }
}

抽象产品

抽象产品,它们都有可能有两种不同的实现。
AbstractProductA和AbstractProductB是两个抽象产品,之所以为抽象,是因为它们都有可能有两种不同的实现。例如User和Department。而ProductA1、ProductA2和ProductB1、ProductB2就是对两个抽象产品的具体分类的实现。例如SqlServerUser,SqlServerDepartment。

通常是在运行时刻再创建一个ConcreteFactory类的实例,这个具体的工厂再创建具有特定实现的产品对象,也就是说,为创建不同的产品对象,客户端应使用不同的具体工厂。

public abstract class AbstractProductA {

}
public abstract class AbstractProductB {

}

具体产品

对抽象产品的具体实现。

public class ProductA1 extends AbstractProductA {
}
public class ProductA2 extends AbstractProductA {
}
public class ProductB1 extends AbstractProductB {
}
public class ProductB2 extends AbstractProductB {
}

抽象工厂模式的优点和缺点

优点:
1)易于交换产品系列,由于具体工厂类,例如IFactory factory= new AccessFactory(),在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。

2)它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。例如:客户端只认识IUser和IDepartment,至于它是SQL Server实现还是Access实现就不知道了。

问题:如果要增加项目表Project,需要改动哪些地方?
需要增加;IProject、SqlServerProject、AccessProject
需要更改:IFactroy、SqlServerFactory、AccessFactory

5)重点:使用简单工厂改进抽象工厂

去除IFactory、SqlServerFactory、AccessFactory三个工厂类,取而代之的是DataAccess。

DataAccess

public class DataAccess {
    // 数据库名称
    private static String db = "SqlServer";

//    private static String db = "Access";
    public static IUser createUser() {
        IUser result = null;
        // 由于db的事先设置,所以此处可以根据选择实例化出相应的对象。
        switch (db) {
        case "SqlServer":
            result = new SqlServerUser();
            break;
        case "Access":
            result = new AccessUser();
            break;
        }
        return result;
    }

    public static IDepartment createDepartment() {
        IDepartment result = null;
        switch (db) {
        case "SqlServer":
            result = new SqlServerDepartment();
            break;
        case "Access":
            result = new AccessDepartment();
            break;
        }
        return result;
    }
}

客户端

客户端没有出现任何一个SQLServer或Access的字样,达到了解耦的目的。

public class Client {

    public static void main(String[] args) {
        User user = new User();
        Department department = new Department();
        
        // 直接得到实际的数据库访问实例,而不存在任何依赖
        IUser iuser = DataAccess.createUser();
        iuser.insert(user);
        iuser.getUser(1);

        // 直接得到实际的数据库访问实例,而不存在任何依赖
        IDepartment iDepartment = DataAccess.createDepartment();
        iDepartment.insert(department);
        iDepartment.getDepartment(1);

    }

}

在这里插入图片描述

6)重点:反射+抽象工厂实现数据访问程序

public class DataAccess {
    // 数据库名称
    private static String db = "SqlServer";
//    private static String db = "Access";

    public static IUser createUser() throws Exception {
        Class<?> clazz = Class.forName("com.studio.abstractfactory.version6." + db + "User");
        return (IUser) clazz.newInstance();
    }

    public static IDepartment createDepartment() throws Exception {
        Class<?> clazz = Class.forName("com.studio.abstractfactory.version6." + db + "Department");
        return (IDepartment) clazz.newInstance();
    }
}

7)重点:反射+配置文件实现数据访问程序

public class DataAccess {

    public static String db = null;
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("config/db.properties"));
            db = (String) properties.get("db");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static IUser createUser() throws Exception {
        Class<?> clazz = Class.forName("com.studio.abstractfactory.version7." + db + "User");
        return (IUser) clazz.newInstance();
    }

    public static IDepartment createDepartment() throws Exception {
        Class<?> clazz = Class.forName("com.studio.abstractfactory.version7." + db + "Department");
        return (IDepartment) clazz.newInstance();
    }
}

在这里插入图片描述

客户端

public class Client {

    public static void main(String[] args) throws Exception {
        User user = new User();
        Department department = new Department();
        
        // 直接得到实际的数据库访问实例,而不存在任何依赖
        IUser iuser = DataAccess.createUser();
        iuser.insert(user);
        iuser.getUser(1);
        // 直接得到实际的数据库访问实例,而不存在任何依赖
        IDepartment iDepartment = DataAccess.createDepartment();
        iDepartment.insert(department);
        iDepartment.getDepartment(1);
    }

}

在这里插入图片描述
注:本文内容源自程杰的《大话设计模式》

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值