• 大话设计模式读书笔记(十二) 抽象工厂模式


    抽象工厂模式:

    书中通过小菜的公司因为新的项目需求,需要将原来的SQL SERVER改为Access,而引出需求。写一个数据访问(“新增用户”,“得到用户”),假设只有name和Id 两个字段。

    未使用设计模式代码:

    用户类
    public class User {
    	private String name;
    	private String id;
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	public User(String name, String id) {
    		super();
    		this.name = name;
    		this.id = id;
    	}
    }
    SqlServerUser 类,用于操作User表
    public class SqlServerUser {
    	public void insert(User user){
    		System.out.println("在Sql server插入对象"+user.getName());
    	}
    	
    	public User getUser(String id){
    		System.out.println("在Sql server中根据id查找一条user数据");
    		return null;
    	}
    }
    

    主程序:
    public class Main {
    	public static void main(String[] args) {
    		User user=  new User("小菜", "1");
    		SqlServerUser ss = new SqlServerUser();
    		ss.insert(user);
    		ss.getUser("1");
    	}
    }
    而不能换数据库的原因,就在于上面代码中的SqlServerUser ss = new SqlServerUser();具体的使用哪个数据库已经写死,如果这里写的很灵活,使用多带,ss.insert()和ss.getUser(""),就不需要考虑具体是哪一个数据库了。于是引出了工厂模式。

    简单工厂模式代码实现:

    抽象工厂接口:
    public interface IFactory {
    	public IUser concreteIUser();
    }
    

    具体工厂类:
    public class MysqlFactory implements IFactory{
    	@Override
    	public IUser concreteIUser() {
    		return new MysqlUser();
    	}
    }
    public class SqlServerFactory implements IFactory{
    	@Override
    	public IUser concreteIUser() {
    		// TODO Auto-generated method stub
    		return new SqlServerUser();
    	}
    
    
    }

    IUser接口,用于数据库访问
    public interface IUser {
    	public void insert(User user);
    	public User getUser(String id);
    }
    

    数据库访问类具体实现:
    public class MysqlUser implements IUser{
    	@Override
    	public void insert(User user){
    		System.out.println("在Mysql插入对象"+user.getName());
    	}
    	@Override
    	public User getUser(String id){
    		System.out.println("在Mysql中根据id查找一条user数据");
    		return null;
    	}
    }
    public class SqlServerUser implements IUser{
    	@Override
    	public void insert(User user){
    		System.out.println("在Sql server插入对象"+user.getName());
    	}
    	@Override
    	public User getUser(String id){
    		System.out.println("在Sql server中根据id查找一条user数据");
    		return null;
    	}
    }
    

    主程序方法
    public class Main {
    	public static void main(String[] args) {
    		User user=  new User("小菜", "1");
    		IFactory factory = new SqlServerFactory();
    		IUser ss =factory.concreteIUser();
    		ss.insert(user);
    		ss.getUser("1");
    	}
    }
    

    这样,如果要更改数据库,只需要更改IFactory factory = new SqlServerFactory()这句话,改成想对应的数据库就可以了。
    然而,数据库实际中不仅仅有一个User表,还会有很多其他的表,而Mysql 和Sql 又是两个不同的大类,
    解决这种设计了多个产品系列的问题,有一个专门的设计模式------抽象工厂模式。

    抽象工厂模式:

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

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

    优点:1、易于交换产品系列,在一个应用中只需要在初始化的时候出现一次,这使得改变一个应用的具体工厂变得容易,它只需要改变具体工厂即可使用不同的产品配置。
    2、它让具体的创建实例过程和客户端分离,客户端是通过他们的抽象接口来操纵实例,产品的具体类名也被产品的具体工厂分离,不会出现在客户端代码中。

    缺点:
    在新增项目是改动较大。

    反射+抽象工厂模式:

    通过反射,只需要将IFactory、MysqlFactory、SqlServerFactory和并成一个DataAccess类。
    代码实现:

    public class DataAccess {
    	//使用哪个数据库
    	public final String DATANAME ="Mysql"
    	//该类在哪个包下
    	private String packageName = "abstractFactory.reflect";
    	public IUser concreteIUser() throws Exception{
    		//通过类的地址 ,使用反射来创建对象
    		Class<?> z = Class.forName(packageName+"."+dataName+"User");
    		IUser user = (IUser) z.newInstance();
    		return user;
    	}
    }

    这样,在需要改动数据库时,只需要把DATANAME改为SqlServer即可。

    反射+配置文件实现访问数据库:

    这里我使用的是properties。

    具体代码如下

    public class DataAccess {
    	 //使用哪个数据库
    	static String dataName;
    	//该类在哪个包下
    	private String packageName = "abstractFactory.reflect";
    	public IUser concreteIUser() throws Exception{
    		//通过类的地址 ,使用反射来创建对象
    		Class<?> z = Class.forName(packageName+"."+dataName+"User");
    		IUser user = (IUser) z.newInstance();
    		return user;
    	}
    	static{
    		Properties p = new Properties();
    		InputStream is = null;
    		try {
    			is = DataAccess.class.getClassLoader().getResourceAsStream("database.properties");
    			p.load(is);
    			dataName = p.getProperty("dataName");
    		} catch (Exception e) {
    			e.printStackTrace();
    		}finally {
    			try {
    				is.close();
    			} catch (IOException e) {
    			}
    		}
    	}
    }
    

    databasse.properties:

    dataName=Mysql

    这样,只需要在配置文件中更改dataName,就可以实现更改数据库,连DataAccess类都不需要改动。



  • 相关阅读:
    Educational Codeforces Round 58
    Educational Codeforces Round 59
    Codeforces Round #534 (Div. 2)
    Codeforces Round #531 (Div. 3)
    Codeforces Round #536 (Div. 2)
    Codeforces Round #530 (Div. 2)
    Codeforces Round #533 (Div. 2)
    Codeforces Round #535 (Div. 3)
    Codeforces Round #532 (Div. 2)
    Codeforces Round #538 (Div. 2)
  • 原文地址:https://www.cnblogs.com/xsyfl/p/6842510.html
Copyright © 2020-2023  润新知