zoukankan      html  css  js  c++  java
  • 大话设计模式读书笔记(十二) 抽象工厂模式

    抽象工厂模式:

    书中通过小菜的公司因为新的项目需求,需要将原来的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类都不需要改动。



  • 相关阅读:
    PyQt作品 – PingTester – 多点Ping测试工具
    关于和技术人员交流的一二三
    Pyjamas Python Javascript Compiler, Desktop Widget Set and RIA Web Framework
    Hybrid Qt applications with PySide and Django
    pyjamas build AJAX apps in Python (like Google did for Java)
    PyQt 维基百科,自由的百科全书
    InfoQ:请问为什么仍要选择Java来处理后端的工作?
    Eric+PyQt打造完美的Python集成开发环境
    python select module select method introduce
    GUI Programming with Python: QT Edition
  • 原文地址:https://www.cnblogs.com/xsyfl/p/6842510.html
Copyright © 2011-2022 走看看