模式11. 抽象工厂模式-Java

1.定义

提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类

2.借助(数据库访问)场景理解

2.1单类的时候,只需工厂方法模式

对象:用户

数据库:数据库:两种方式 SQLserver以及 Access

用工厂方法模式的数据库访问程序

在这里插入图片描述

(1)Iuser接口

package com.factory;

//IUSer接口,用于客户端访问,解除与具体数据库访问的耦合
public interface Iuser {
    void Insert(User user);
    User GetUser(int id);
}

(2)

package com.factory;
//用于访问Sql Server的User
public class SqlserverUser implements  Iuser{
    @Override
    public void Insert(User user) {
        System.out.println("在Sql Server中给User表增加一条记录");
    }

    @Override
    public User GetUser(int id) {
        System.out.println("在Sql Server中给根据ID得到User表的一条记录");
        return null;
    }
}

(3)

package com.factory;
//用于访问Access的User
public class AccessUser implements Iuser{
    @Override
    public void Insert(User user) {
        System.out.println("在Access中给User表增加一条记录");
    }

    @Override
    public User GetUser(int id) {
        System.out.println("在Access中给根据ID得到User表的一条记录");
        return null;
    }
}

(4)

package com.factory;

//定义一个创建访问User表对象的抽象的工厂接口
public interface IFactory {
    Iuser CreateUser();
}

(5)

package com.factory;

//实例化SqlserverUser

public class SqlServerFactory implements IFactory {
    @Override
    public Iuser CreateUser() {
        return new SqlserverUser();
    }
}

(6)

package com.factory;

public class AccessFactory implements IFactory{
    @Override
    public Iuser CreateUser() {
        return  new  AccessUser();
    }
}

(7)客户端代码

package com.factory;

public class AccessFactory implements IFactory{
    @Override
    public Iuser CreateUser() {
        return  new  AccessUser();
    }
}

(8)测试结果

在Sql Server中给User表增加一条记录
在Sql Server中给根据ID得到User表的一条记录

2.2多类的时候,体现抽象工厂模式

对象: 用户,以及部门

数据库:两种方式 SQLserver以及 Access

在这里插入图片描述

和2.1相比,增加如下代码

(1) 部门类

package com.abstractfactory;

public class Department {
    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;
    }
}

(2)Idepartment接口, 用于客户端访问,解除与具体数据库

package com.abstractfactory;

public interface Idepartment {
    void Insert(Department department);
    Department GetUser(int id);
}

(3)SqlServerDepartment类,用于Sqlserver操作department表

package com.abstractfactory;

public class SqlserverDepartment implements  Idepartment{
    @Override
    public void Insert(Department department) {
        System.out.println("在SqlServer中向department表插一条记录");

    }

    @Override
    public Department GetUser(int id) {
        System.out.println("在Sqlserver中给根据ID得到department表的一条记录");
        return null;
    }
}

(4)同理Accessdepartment

package com.abstractfactory;

public class AccessDepartment implements Idepartment{
    @Override
    public void Insert(Department department) {
        System.out.println("在ACcess中向department表插一条记录");

    }

    @Override
    public Department GetUser(int id) {
        System.out.println("在Access中给根据ID得到department表的一条记录");
        return null;
    }
}

(5)修改Ifactory

package com.abstractfactory;

//定义一个创建访问User表对象的抽象的工厂接口
public interface IFactory {
    Iuser CreateUser();
    Idepartment CreateDepartment();
}

(6)修改SqlserverFactory

package com.abstractfactory;

//实例化SqlserverUser

public class SqlServerFactory implements IFactory {
    @Override
    public Iuser CreateUser() {
        return new SqlserverUser();
    }

    @Override
    public Idepartment CreateDepartment() {
        return  new SqlserverDepartment();
    }
}

(7)修改AccessFactory

package com.abstractfactory;

public class AccessFactory implements IFactory {
    @Override
    public Iuser CreateUser() {
        return  new AccessUser();
    }

    @Override
    public Idepartment CreateDepartment() {
        return  new AccessDepartment();
    }
}

(8)客户端

package com.abstractfactory;

public class Client {
    public static void main(String[] args) {
        User user =new User();
        Department department=new Department();
        IFactory factory=new AccessFactory();//若要改变为Access数据库,只需将本句改为

       // IFactory factory=new SqlServerFactory();
        Iuser iuser=factory.CreateUser();  //与具体数据库访问解除了依赖
        Idepartment idepartment=factory.CreateDepartment();

        iuser.Insert(user);
        iuser.GetUser(1);

        idepartment.Insert(department);
        idepartment.GetUser(1);

    }
}

(9)测试结果

在Access中给User表增加一条记录
在Access中给根据ID得到User表的一条记录
在ACcess中向department表插一条记录
在Access中给根据ID得到department表的一条记录

3.抽象工厂模式优缺点

在这里插入图片描述

  • Ifactory中包含所有产品创建的抽象方法。

  • 为创建不同的产品对象,客户端使用不同的具体工厂。

    优点

    • 便于交换产品系列,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,使得改变一个应用的具体工厂变得非常容易,只需要改变具体工厂即可使用不同的产品配置
    • 让具体的创建实例过程与客户端分离。客户端时通过他们的抽象接口比如Iuser操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中

    缺点

    增加实体类的时候要改动很多地方,比如增加company表,就需要增加ICompany接口,SqlserverFactory,AccessFactory,还需要改动Ifactory, SqlserverCompany以及AccessFactory

4.用简单工厂一定程度优化抽象工厂

在这里插入图片描述

设计Dataaccess类,

package com.simpleFactory;



public class DataAccess {
    private static  String db="SqlServer";  //在这里该数据库类型
    //private  static  String db="Access";
    public  static  Iuser CreateUser(){
        Iuser result=null;
        switch (db){  //前边已经选好了数据库
            case "Sqlserver":
                result=new SqlserverUser();
                break;
            case  "Access":
                result=new AccessUser();
                break;
        }
        return  result;
    }
    public  static Idepartment CreateIdepartement(){
        Idepartment result=null;
        switch (db){
            case "Sqlserver":
                result=new SqlserverDepartment();
                break;
            case  "Access":
                result=new AccessDepartment();
                break;
        }

        return  result;
    }
}

更改客户端

package com.simpleFactory;


public class Client {
    public static void main(String[] args) {
        User user =new User();
        Department department=new Department();
	//因为事先选好了用的数据库,所以可以直接得到数据库访问实例,客户不需要了解是用的什么数据库
        Iuser iuser=DataAccess.CreateUser();  //因为设置的都是静态函数,直接用
        Idepartment idepartment= (Idepartment) DataAccess.CreateIdepartement();

        iuser.Insert(user);
        iuser.GetUser(1);

        idepartment.Insert(department);
        idepartment.GetUser(1);

    }
}

简单工厂方法的确实现了客户端不需要知道Sqlser和ACcess数据库, 但是如果再加一个数据库比如oracle,就不是抽象工厂方法中增加oracleFactory那么简单了,需要再DataAccess的每个函数中的switch中加Case

5.反射+抽象工厂模式

  • 利用反射,使用字符串来实例化对象。而不再是写死再程序中

在这里插入图片描述

JAVA反射机制是就是运行的状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。通过反射机制可以动态的访问类的属性和方法以及字段。

最常用的反射机制就是:

()Class.forName("obj name").newInstance();
package com.reflection;


public class DataAccess {
    private static String AssemblyName="com.reflection";  //根目录Src下的路径
    private static String db="Sqlserver"; //可以替换成任意类型的数据库,比如access

    public  static Iuser CreateUser() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
      String classname=AssemblyName+"."+db+"User";
      return (Iuser)Class.forName(classname).newInstance();
        //根据字符串 "com.reflection.SqlserverUser"匹配com.reflection.SqlserverUser类
    }
    public  static Idepartment CreateIdepartment() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        String classname=AssemblyName+"."+db+"Department";
        return (Idepartment) Class.forName(classname).newInstance();
    }

}

成功的前提是com.reflection.SqlserverUser,SqlserverDepartment这些类存在

客户端没有变化

package com.reflection;


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

        Iuser iuser= DataAccess.CreateUser();
        Idepartment idepartment= DataAccess.CreateIdepartment();

        iuser.Insert(user);
        iuser.GetUser(1);

        idepartment.Insert(department);
        idepartment.GetUser(1);

    }
}

执行结果

在Sql Server中给User表增加一条记录
在Sql Server中给根据ID得到User表的一条记录
在SqlServer中向department表插一条记录
在Sqlserver中给根据ID得到department表的一条记录

6.用反射+配置文件+抽象工厂模式(end,最理想)

完整代码:

(1)实体类

package com.reflection;

public class User {
    private int _id;
    private  String _name;

    public int get_id() {
        return _id;
    }

    public void set_id(int _id) {
        this._id = _id;
    }

    public String get_name() {
        return _name;
    }

    public void set_name(String _name) {
        this._name = _name;
    }
}

package com.reflection;

public class Department {
    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;
    }
}

(2) 实体表接口,事先客户端与实体表的解耦

package com.reflection;

//IUSer接口,用于客户端访问,解除与具体数据库访问的耦合
public interface Iuser {
    void Insert(User user);
    User GetUser(int id);
}

package com.reflection;

public interface Idepartment {
    void Insert(Department department);
    Department GetUser(int id);
}

(3) 具体数据库操作每个实体

Access数据库

package com.reflection;

//用于访问Access的User
public class AccessUser implements Iuser {
    @Override
    public void Insert(User user) {
        System.out.println("在Access中给User表增加一条记录");
    }

    @Override
    public User GetUser(int id) {
        System.out.println("在Access中给根据ID得到User表的一条记录");
        return null;
    }
}

package com.reflection;

public class AccessDepartment implements Idepartment {
    @Override
    public void Insert(Department department) {
        System.out.println("在ACcess中向department表插一条记录");

    }

    @Override
    public Department GetUser(int id) {
        System.out.println("在Access中给根据ID得到department表的一条记录");
        return null;
    }
}

Sql server数据库

package com.reflection;

//用于访问Sql Server的User
public class SqlserverUser implements Iuser {
    @Override
    public void Insert(User user) {
        System.out.println("在Sql Server中给User表增加一条记录");
    }

    @Override
    public User GetUser(int id) {
        System.out.println("在Sql Server中给根据ID得到User表的一条记录");
        return null;
    }
}

package com.reflection;

public class SqlserverDepartment implements Idepartment {
    @Override
    public void Insert(Department department) {
        System.out.println("在SqlServer中向department表插一条记录");

    }

    @Override
    public Department GetUser(int id) {
        System.out.println("在Sqlserver中给根据ID得到department表的一条记录");
        return null;
    }
}

(4) 数据库抽象工厂, 利用配置文件+反射

使用反射替代了简单工厂的switch

用户改数据库类型,只需在配置文件中改!

db=Access
package com.reflection;

import java.util.ResourceBundle;

public class DataAccess {
    private static String AssemblyName="com.reflection";
    //读取配置文件中的db类型
    ResourceBundle resource1=ResourceBundle.getBundle("com/reflection/App");
    //通过用户输入的来取指定类
    private  String db=resource1.getString("db"); //可以替换成任意类型的数据库,比如access

    public   Iuser CreateUser() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
      String classname=AssemblyName+"."+db+"User";
      return (Iuser)Class.forName(classname).newInstance();
    }
    public   Idepartment CreateIdepartment() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        String classname=AssemblyName+"."+db+"Department";
        return (Idepartment) Class.forName(classname).newInstance();
    }

}

(5)客户端

package com.reflection;


public class Client {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        User user =new User();
        Department department=new Department();
        DataAccess dataAccess=new DataAccess();
        Iuser iuser= dataAccess.CreateUser();
        Idepartment idepartment= dataAccess.CreateIdepartment();

        iuser.Insert(user);
        iuser.GetUser(1);

        idepartment.Insert(department);
        idepartment.GetUser(1);

    }
}

运行结果

在Access中给User表增加一条记录
在Access中给根据ID得到User表的一条记录
在ACcess中向department表插一条记录
在Access中给根据ID得到department表的一条记录
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值