23种设计模式——抽象工厂模式

目录

抽象工厂模式(AbstractFactory)

产品族

理解

UML图

优缺点

应用场景

抽象工厂模式VS和工厂模式

实例

数据访问(工厂方法)

数据访问(抽象工厂)

用简单工厂改造抽象工厂

C#中的反射

Java实现反射+配置文件+抽象工厂数据访问程序


抽象工厂模式(AbstractFactory)

本质:选择产品族的实现

产品族

产品族:不同产品等级的产品集合。

23种设计模式——抽象工厂模式_第1张图片


图中一共有四个产品族,分布于三个产品等级结构中。

产品族+等级结构可以唯一确定一个产品。

理解

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

抽象工厂是指一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象。

23种设计模式——抽象工厂模式_第2张图片

23种设计模式——抽象工厂模式_第3张图片

UML图

23种设计模式——抽象工厂模式_第4张图片

抽象工厂(Abstract Factory):
核心,与商业逻辑无关
具体工厂(Concrete Factory):
在客户端的调用下创建产品的实例,含有选择合适的产品对象的逻辑(与商业逻辑有关)
抽象产品(Abstract Product):
担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
具体产品(Concrete Product):
抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。

优缺点

  • 增加产品族:支持“开放-封闭"原则
  • 增加新产品的等级结构:需要修改所有的工厂角色,不支持“开放-封闭”原则
  • 总之,它以一种倾斜的方式支持增加新的产品族,而不支持增加新的产品等级

应用场景

  • 一个系统不依赖于产品类实例如何被创建、组合和表达的细节时。
  • 一个系统有多于一个的产品族,而系统只消费其中某一产品族时。


抽象工厂模式VS和工厂模式

  • 抽象工厂模式:为创建一组(有多类)相关或依赖的对象提供创建接口。
  • 工厂模式:为一类对象提供创建接口
     

实例

数据访问(工厂方法)

23种设计模式——抽象工厂模式_第5张图片

需要更换Mysql数据库时,只需要增加MysqlUser和MysqlFactory

package com.method;

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 interface IUser {
	void Insert(User user);
	User getUser(int id);

}

public class SqlserverUser implements IUser{

	@Override
	public void Insert(User user) {
		// TODO Auto-generated method stub
		System.out.println("在SqlServer中给User表增加一条记录");
	}

	@Override
	public User getUser(int id) {
		// TODO Auto-generated method stub
		System.out.println("在SqlServer中根据id得到User表一条记录");
		return null;
	}
	
	

}

public class AccessUser implements IUser{

	@Override
	public void Insert(User user) {
		// TODO Auto-generated method stub
		System.out.println("在Access中给User表增加一条记录");
	}

	@Override
	public User getUser(int id) {
		// TODO Auto-generated method stub
		System.out.println("在Access中根据id得到User表一条记录");
		return null;
	}
	

}
public interface IFactory {
	public IUser createUser();

}

public class SqlserverFactory implements IFactory{

	@Override
	public IUser createUser() {
		// TODO Auto-generated method stub
		return new SqlserverUser();
	}
	

}

public class AccessFactory implements IFactory{

	@Override
	public IUser createUser() {
		// TODO Auto-generated method stub
		return new AccessUser();
	}
	

}

实现了增加数据库还不够

如果数据库中要增加其它表,比如Dept表,就需要增加很多类 ,此时用到了抽象工厂模式

数据访问(抽象工厂)

23种设计模式——抽象工厂模式_第6张图片

产品族:两种DBMS

产品等级:两张表

public interface IFactory {
	public IUser createUser();
	public IDept createDept();
}

public class SqlserverFactory implements IFactory{

	@Override
	public IUser createUser() {
		// TODO Auto-generated method stub
		return new SqlserverUser();
	}

	@Override
	public IDept createDept() {
		// TODO Auto-generated method stub
		return new SqlserverDept();
	}
	

}

public class AccessFactory implements IFactory{

	@Override
	public IUser createUser() {
		// TODO Auto-generated method stub
		return new AccessUser();
	}

	@Override
	public IDept createDept() {
		// TODO Auto-generated method stub
		return new AccessDept();
	}
	

}
public class Dept {
	private int did;
	private String dname;
	
	public int getDid() {
		return did;
	}
	public void setDid(int did) {
		this.did = did;
	}
	public String getDname() {
		return dname;
	}
	public void setDname(String dname) {
		this.dname = dname;
	}

}
public interface IDept {
	void Insert(Dept dept);
	User getDept(int did);

}

public class SqlserverDept implements IDept{

	@Override
	public void Insert(Dept dept) {
		// TODO Auto-generated method stub
		System.out.println("在Sqlserver中给Department表增加一条记录");
	}

	@Override
	public User getDept(int did) {
        System.out.println("在Sqlserver中根据id="+did+"得到Department表一条记录");
		return null;
	}
	

}

public class AccessDept implements IDept{

	@Override
	public void Insert(Dept dept) {
		// TODO Auto-generated method stub
		System.out.println("在Access中给Department表增加一条记录");
	}

	@Override
	public User getDept(int did) {
		// TODO Auto-generated method stub
		System.out.println("在Access中根据id="+did+"得到得到Department表一条记录");
		return null;
	}

}
public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		User user=new User();
		IFactory factory1=new SqlserverFactory();
		IUser iu=factory1.createUser();
		iu.Insert(user);
		iu.getUser(1);
		
		Dept dept=new Dept();
		IDept idept=factory1.createDept();
		idept.Insert(dept);
		idept.getDept(2);
	}

}

用简单工厂改造抽象工厂

用Database类代替IFactory,SqlserverFactory,AccessFactory三个类

客户端无需出现Access和Sqlserver,而是通过事先设置的db值来选择DBMS,实现了解耦

如果要增加Mysql数据库,就需要在Database类的switch中增加case"Mysql"语句

23种设计模式——抽象工厂模式_第7张图片

public class DataBase {
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 IDept createDept() {
		IDept result=null;
		switch(db) {
		case "Sqlserver":
			result=new SqlserverDept();
			break;
		case "Access":
			result=new AccessDept();
			break;
		}
		return result;
	}

}
public class Main {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		User user=new User();
		Dept dept=new Dept();
		
		IUser iu=DataAccess.createUser();
		iu.Insert(user);
		iu.getUser(1);
		
		IDept idept=DataAccess.createDept();
		idept.Insert(dept);
		idept.getDept(2);
	}

}

有没有办法可以不写明以上switch语句中的case"SqlserverUser"这样的话呢?

由此我们引入反射

C#中的反射

常规:当某个角色需要另一个角色的协助时,通常由调用者来创建被调用者的实例

依赖注入:创建被调用者的工作不再由调用者来完成(因此叫控制反转),创建被调用者实例的工作通常由Ioc容器来完成,然后注入调用者。

控制反转和依赖注入是同一个概念

23种设计模式——抽象工厂模式_第8张图片

Java实现反射+配置文件+抽象工厂数据访问程序

Java反射允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息

Java反射相关的API在包java.lang.reflect.*中,具体可以参考我这篇文章

关于XML文件解析可以参考我这篇文章

增加一个data2.xml,配置数据库名字

更改DataBase类,负责读取data2.xml文件中的数据库名字

23种设计模式——抽象工厂模式_第9张图片



	
		Access
	
package com.reflect;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.util.Iterator;

public class DataBase {
    private static String db;

    public static String getDb(){
        SAXReader reader = new SAXReader();
        Object obj=null;

        try {
            //获取Document 对象
            Document doc = reader.read("AbstractFactory/conf/data2.xml");
            //获取 xml 根节点
            Element root = doc.getRootElement();
            //遍历根节点,获取子节点
            for (Iterator iter = root.elementIterator(); iter.hasNext(); ) {
                //获取database节点对象
                Element dElement = (Element) iter.next();

                //遍历database节点的子节点
                for (Iterator innerIter = dElement.elementIterator(); innerIter.hasNext(); ) {
                    //获取databases节点的对象
                    Element innerElement = (Element) innerIter.next();
                    db= innerElement.getStringValue();
                }
            }
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return db;

    }
    public static IUser createUser() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String db=getDb();
        Class c = Class.forName("com.reflect."+db+"User");
        Object obj=c.newInstance();
        return (IUser) obj;
    }

    public static IDept createDept() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String db=getDb();
        Class c = Class.forName("com.reflect."+db+"Dept");
        Object obj=c.newInstance();
        return (IDept) obj;
    }
}
package com.reflect;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        User user = new User();
        Dept dept = new Dept();
        IUser iu = DataBase.createUser();
        iu.Insert(user);
        iu.getUser(1);
        IDept id = DataBase.createDept();
        id.Insert(dept);
        id.getDept(1);

    }
}

23种设计模式——抽象工厂模式_第10张图片

需要修改连接的数据库时,只需要修改data2.xml

 23种设计模式——抽象工厂模式_第11张图片

 

你可能感兴趣的:(设计模式,设计模式)