package abstracFactoryModel;
/**
 *这里是连接数据库的一个例子   就不写一遍的连接了  直接用工厂方法模式来实现 
 */
public class Commonly {
  public static void main(String[] args) {
    User user = new User();
    Ifactory ifactory = new MysqlFctory();//如果换成了Oracle 数据库 那么把这里换成OracleFctory就行了
    IUser  iUser = ifactory.CreateUser();
    //插入User  获取User
    iUser.Insert(user);
    iUser.GetUser(2);
    //一个系统不可能只有一个User表  如果加一个其他表呢 比如部门表需要增加代码 看Commonly2
    Depaertment depaertment = new Depaertment();
    IDepaertment iDepaertment = ifactory.CreateDepartment();
    //插入Department 根据id获取Department
    iDepaertment.Insert(depaertment);
    iDepaertment.GetDepaertment(1);
    //!!!! 只有一个user类和user操作的时候 是只需要工厂方法模式的  
    //但现在显然数据库中有很多表 而且MySQL 和 oracle 有事2个不同的分类 所以解决这种
    //涉及到多个产品系列的问题  有一个专门的工厂模式--》抽象工厂模式
  }
}
/*
 * 用户类
 */
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;
  }
}
/*
 * User操作抽象类
 */
interface IUser{
  void Insert(User user);
  User GetUser(int i);
}
/*
 * 具体实现(Mysql)
 */
class MysqlUser implements IUser{
  public void Insert(User user) {
    System.out.println("在mysql中插入用户数据");
  }
  public User GetUser(int i) {
    System.out.println("根据id从mysql中获取数据");
    return null;
  }
}
/*
 * 具体实现(Oracle)
 */
class OracleUser implements IUser{
  public void Insert(User user) {
    System.out.println("在Oracle中插入用户数据");
  }
  public User GetUser(int i) {
    System.out.println("根据id从Oracle中获取数据");
    return null;
  }
}
// 通过工厂获取具体对象 这就是工厂方法  
/*
 *抽象工厂
 */
interface Ifactory{
  IUser CreateUser();
  // 新增++++ 获取department  
  IDepaertment CreateDepartment();
}
/*
 * mysql工厂
 */
class MysqlFctory implements Ifactory{
  public IUser CreateUser() {
    return new MysqlUser();
  }
  // 新增++++ 获取department  
  public IDepaertment CreateDepartment() {
    return new MysqlDepaertment();
  }
}
/*
 * Oracle工厂
 */
class OracleFctory implements Ifactory{
  public IUser CreateUser() {
    return new OracleUser();
  }
  // 新增++++ 获取department  
  public IDepaertment CreateDepartment() {
    return new OracleDepaertment();
  }
}
package abstracFactoryModel;
/**
 *这里是连接数据库的一个例子   就不写一遍的连接了  直接用工厂方法模式来实现 
 */
public class Commonly2 {
  public static void main(String[] args) {
    User user = new User();
    Ifactory ifactory = new MysqlFctory();//如果换成了Oracle 数据库 那么把这里换成OracleFctory就行了
    IUser  iUser = ifactory.CreateUser();
    //插入User  获取User
    iUser.Insert(user);
    iUser.GetUser(2);
  }
}
/*
 * 如果增加一个部门 需要增加如下代码
 */
/*
 * 这个类是必不可少的 
 */
class Depaertment{
  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;
  }
}
/*
 * 抽象
 */
interface IDepaertment{
  void Insert(Depaertment depaertment);
  Depaertment GetDepaertment(int id);
}
/*
 * Mysql实现
 */
class MysqlDepaertment implements IDepaertment{
  public void Insert(Depaertment depaertment) {
    System.out.println("Mysql插入Depaertment");
  }
  public Depaertment GetDepaertment(int id) {
    System.out.println("根据id从Mysql获取Depaertment");
    return null;
  }
}
/*
 * Oracle实现
 */
class OracleDepaertment implements IDepaertment{
  public void Insert(Depaertment depaertment) {
    System.out.println("Oracle插入Depaertment");
  }
  public Depaertment GetDepaertment(int id) {
    System.out.println("根据id从Oracle获取Depaertment");
    return null;
  }
}
//----------还没完  去Commonly.java 中看一下  还需要在Ifactory  MysqlFctory  OracleFactory 中添加内容 :新增++++
package abstracFactoryModel;
/*
 * 抽象工厂模式:
 * 提供一个创建一系列相关或相互依赖对象的接口 而无序指定他们具体的类
 * 
 * 最大的好处就是交换产品系列 ,因为类似于 Ifactory ifactory = new MysqlFctory(); 
 * 在一个应用中只初始化一次 这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体的工厂就可以使用不同的产品配置
 * 比如说这里:把 Ifactory ifactory = new MysqlFctory();  修改为 Ifactory ifactory = new OracleFctory();
 * 后边所有的操作就会变成针对Oracle的操作 很方便
 * 
 *  
 * 第二大好处是:它让具体的创建实例过程与客户端分离 客户端通过抽象接口来操作实例,
 * 产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中 
 *  
 *  
 *  缺点:如果需求来自于增加功能那么就非常可悲了  就拿我们在Commonly2中增加Deprtment似的  需要修改好多地方 还要添加好多东西
 *  
 */
public class AbstracFactoryModel {
    public static void main(String[] args) {
    }
}
/*
 * 用简单工厂模式来代替  用DataAccess 代替 Ifactory  MysqlFactory  OracleFactory 
 * 
 * 但是如果想再加一个类别 比如sqlsever 需要在DataAccess中加case 分支了 
 * 
 * 
 * 用反射!!!-->DataAccessRflect
 * 可以看到DataAccessRflect 这个类中用了反射  用了反射之后 再添加新的分类是不需要添加case分支de
 * 但是 但是 但是 还是需要修改个别地方的 比如说我想把mysql换成oracle 需要修改成员字段db 
 *怎么办???
 *
 *用配置文件!!!
 *
 * 
 * 
 * 
 */
class DataAccess{
    /*
     * 只读属性
     */
    private  static   String db = "mysql";
    public String getDb() {
        return db;
    }
    static IUser  CreateUser(){
        IUser iUser  = null;
        switch (db) {
        case "mysql":
            iUser = new MysqlUser();
        case "oracle":
            iUser = new OracleUser();
        default:
            break;
        }
        return iUser;
    }
    public static IDepaertment  CreateDepartment(){
        IDepaertment iDepaertment  = null;
        switch (db) {
        case "mysql":
            iDepaertment = new MysqlDepaertment();
        case "oracle":
            iDepaertment = new OracleDepaertment();
        default:
            break;
        }
        return iDepaertment;
    }
}
class DataAccessRflect{
    //包路径
    private  static   String packagePath = "abstracFactoryModel";
    //类名
    private  static   String db = "Mysql";
    static IUser  CreateUser(){
         IUser iUser = null;
         String className = packagePath+db+"User";
        try {
            //这里用了反射 就不需要case分支了 如果再添加一种类型  这里是不需要改变的
             iUser =  (IUser) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
         return iUser;
    }
    public static IDepaertment  CreateDepartment(){
        IDepaertment Department = null;
         String className = packagePath+db+"Department";
        try {
            Department =  (IDepaertment) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
         return Department;
    }
}
class DataAccessRConfig{
    //包路径
    private  static   String packagePath = "abstracFactoryModel";
    //类名
    static IUser  CreateUser(){
         IUser iUser = null;
         String db = getDBfromXml();
         String className = packagePath+db+"User";
        try {
            //这里用了反射 就不需要case分支了 如果再添加一种类型  这里是不需要改变的
             iUser =  (IUser) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
         return iUser;
    }
    public static IDepaertment  CreateDepartment(){
        IDepaertment Department = null;
        String db = getDBfromXml();
         String className = packagePath+db+"Department";
        try {
            Department =  (IDepaertment) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
         return Department;
    }
    public static String getDBfromXml(){
        //这里省略了从xml 或者其他配置文件中读取属性的值
        //大致结构是这样 但是不同的文件有不同的标签 我这里的标签是不对的 但是结构就是这么个意思
        /*<?xml version="1.0"  encoding="utf-8" ?>
<configuratin>
<setting>
<add key="DB" value="Mysql">
</setting>
</configuratin>*/
        return "Mysql";
    }
}