概念
1.简单工厂: 简单工厂模式中工厂为具体工厂,产品为抽象产品,由工厂实例创建产品实例。
2.工厂方法模式: 定义一个用于创建对象的接口,让其子类确定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
3.抽象工厂模式: 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
1.简单工厂案例及解析
类图:
这是一个简单工厂的类图,我们可以从一个案例中来对它进行讲解:
比如小明突发奇想,想做一个关于计算器的编程代码,小明第一次编写代码时,将所有的代码都写在一个类里面,而且只有加减乘除四种方法。
从上述的描述中,我们不难看出,如果我们在添加一个功能的话,那么只能在本类中进行更改,在多添加十个功能,那么最后可能只有自己才能看懂。所以,我们使用简单工厂来进行改进。
代码:
运算类
public class Operation {
private double numberA=0;
private double numberB=0;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public double GetResult(){
double result = 0;
return result;
}
}
其他具体逻辑类
public class OperationAdd extends Operation{
@Override
public double GetResult(){
double result = 0;
result=getNumberA()+getNumberB();
return result;
}
}
public class OperationSub extends Operation{
@Override
public double GetResult(){
double result = 0;
result=getNumberA()-getNumberB();
return result;
}
}
public class OperationMul extends Operation{
@Override
public double GetResult(){
double result = 0;
result=getNumberA()*getNumberB();
return result;
}
}
public class OperationDiv extends Operation{
@Override
public double GetResult(){
double result = 0;
if (getNumberB()==0) {
System.out.println("除数不能为零!");
}else {
result=getNumberA()/getNumberB();
}
return result;
}
}
简单运算工厂类
public class OperationFactory {
public static Operation createOperate(String operate){
Operation oper=new Operation();
switch (operate){
case "+":
oper=new OperationAdd();
break;
case "-":
oper=new OperationSub();
break;
case "*":
oper=new OperationMul();
break;
case "/":
oper=new OperationDiv();
break;
}
return oper;
}
}
客户端代码
public class Text {
public static void main(String[] args) {
Operation op=OperationFactory.createOperate("+");
op.setNumberA(1);
op.setNumberB(2);
double result = op.GetResult();
System.out.println(result);
}
}
实现
3.0
总结:
在简单工厂里面,客户端操作人员,不需要知道具体的逻辑,只要进行数字的输入和运算的字符输入,即可知道最后的答案。而且我们在修改其中的某一个具体的类时,也不会影响到其他的类。
特点:使用静态的方法通过接收参数的不同来返回不同的实例。
缺点:当我们添加新的开跟或者平方等其他运算时,就违反了开放-封闭原则。
优点:灵活性高。在工厂类中包含了必要的逻辑,根据客户端的条件动态的实例化相关的类,对客户端来说,去掉了与产品的具体依赖。
2.工厂方法案例及解析
类图:
解析:
不难看出,工厂方法是简单工厂的迭代升级,现在是由具体的工厂来进行每个类的实例化。
我们在这里再看一个案例,小明的同学小红,继承了雷锋精神。经常到一个老人家中帮忙,近几天,小红得了病不能再去帮助老人了,就委托了小明和社区的志愿者去老人家中帮忙。
代码:
雷锋类:
public class LeiFeng {
public void Sweep(){
System.out.println("扫地");
}
public void Wash(){
System.out.println("洗衣");
}
public void BuyRice(){
System.out.println("买米");
}
}
学生和社区志愿者继承雷锋类:
public class Undergraduate extends LeiFeng{
}
public class Volunteer extends LeiFeng {
}
雷锋工厂
public interface IFactory {
LeiFeng CreateLeiFeng();
}
继承雷锋精神的人
学生工厂:
public class UndergraduateFactory implements IFactory {
@Override
public LeiFeng CreateLeiFeng() {
return new Undergraduate();
}
}
社区志愿者工厂:
public class VolunteerFactory implements IFactory {
@Override
public LeiFeng CreateLeiFeng() {
return new Volunteer();
}
}
客户端代码:
public class Test {
public static void main(String[] args) {
IFactory factory=new UndergraduateFactory();
LeiFeng student=factory.CreateLeiFeng();
student.Sweep();
student.BuyRice();
student.Wash();
}
}
实现:
扫地
买米
洗衣
总结:
工厂方法针对每一个继承雷锋类的人提供一个工厂类,如果我们还要添加其他继承雷锋精神的人,那么直接添加类即可。
缺点:不易于维护,假如某个具体类要进行修改,很可能需要修改对应的工厂类。当同时修改多处代码时,对工厂类的修改就会变得相当的麻烦。
优点:创建对象的接口,让子类去决定具体实例化的对象,把内部逻辑判断转移到客户端代码。工厂方法克服了简单工厂违背开放-封闭原则的缺点,不用每次新增新类型产品都修改工厂类,又保持了封装对象创建过程的优点。
3.抽象工厂案例及解析
类图:
案例:
这天,小明在工作时遇到一个项目,项目的要求是:客户现在希望自己的数据可以从两种数据库的存取数据,并且现在有两张表,每个表都有一个添加和查询的方法。
那么我们怎么实现具体的代码呢?
IUser接口
public interface IUser {
void Insert(User user);
User GetUser(int id);
}
public interface IDepartment {
void Insert(Department department);
User GetUser(int id);
}
public interface IFactory {
IUser CreateUser();
IDepartment CreateDepartment();
}
Sqlserver数据库对应操作所创建的类
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;
}
}
public class SqlserverDepartment implements IDepartment {
@Override
public void Insert(Department department) {
System.out.println("在SQL server中给Department表增加一条记录");
}
@Override
public User GetUser(int id) {
System.out.println("在SQL server中根据ID得到Department表一条记录");
return null;
}
}
public class SqlServerFactory implements IFactory {
@Override
public IUser CreateUser() {
return new SqlserverUser();
}
@Override
public IDepartment CreateDepartment() {
return new SqlserverDepartment();
}
}
从这里开始就是 Access数据库对应操作所创建的类
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;
}
}
public class AccesssDepartment implements IDepartment {
@Override
public void Insert(Department department) {
System.out.println("在Access中给Department表增加一条记录");
}
@Override
public User GetUser(int id) {
System.out.println("在Access中根据ID得到Department表一条记录");
return null;
}
}
public class AccessFactory implements IFactory {
@Override
public IUser CreateUser() {
return new AccessUser();
}
@Override
public IDepartment CreateDepartment() {
return new AccesssDepartment();
}
}
客户端代码:
public static void main(String[] args) {
User user = new User();
Department department = new Department();
//IFactory factory=new SqlServerFactory();
IFactory factory=new AccessFactory();
IUser iu=factory.CreateUser();
iu.Insert(user);
iu.GetUser(1);
IDepartment id=factory.CreateDepartment();
id.GetUser(1);
id.Insert(department);
}
输出代码:
在Access中给user表增加一条记录
在Access中根据ID得到user表一条记录
在Access中根据ID得到Department表一条记录
在Access中给Department表增加一条记录
总结:
看完代码,我们可以看出抽象工厂模式是对于工厂方法的迭代升级,抽象工厂模式是针对于多对多的关系。可以增加新的产品线(方法)。
缺点:抽象工厂模式在于难以应付“新对象”的需求变动,比如我在加一个数据库。难以支持新种类的产品。
优点:分离具体的类,客户端通过抽象接口操纵实例,产品的类名也在具体工厂实现中被分离,不会出现在客户端代码中。