目录
简单工厂模式
工厂方法模式
简单工厂 VS 工厂方法
抽象工厂模式:
拓展:
利用简单工厂模式优化抽象工厂
利用反射+抽象工厂 进行优化
反射+配置文件+抽象工厂进行优化
简单工厂模式
优点:简单工厂模式的最大优点在于工厂类包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类。对与客户端来说去除了与具体产品的依赖。
缺点:违背开发-封闭原则(每增加一个功能类,都要在工厂方法里加逻辑判断)
适用场景:简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。
结构图:
实例:(简单工厂和功能类:依赖关系)
工厂方法模式
-
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
-
在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。
优点:
-
工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。
-
封装了对象的创建,使得要更换对象时,不需要做大的改动就可实现,降低了客户程序与产品对象的耦合。
-
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
缺点:
-
类的个数容易过多,增加复杂度。(需要有多个具体工厂)
-
增加了系统的抽象性和理解难度
适用场景:
-
当客户程序不需要知道要使用对象的创建过程。
-
客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。
结构图:
实例:
简单工厂 VS 工厂方法
-
工厂方法模式实现时,客户端需要决定实例化哪一个工厂类(子类),选择判断的问题还是存在的。也就是说工厂方法把简单工厂的内部逻辑判断转移到了客户端代码来进行。你想要增加功能,本来是修改工厂类的,而现在是修改客户端。
-
都集中封装了对象的创建,使得要更换对象时,不需要做大的改动就可以实现,降低了客户程序与产品对象的耦合。
抽象工厂模式:
抽象工厂模式为创建一组对象提供了一种解决方案。 与工厂方法模式相比, 抽象工厂模式中的具体工厂不只是创建一种具体对象,它负责创建一组(族)具体对象。
优点:
-
抽象工厂模式隔离了具体类的生成, 使得客户并不需要知道什么被创建。 由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口, 因此只需改变具体工厂的实例, 就可以在某种程度上改变整个软件系统的行为。
-
当一个族中的多个对象被设计成一起工作时, 它能够保证客户端始终只使用同一个族中的对象。
-
增加新的族很方便, 无须修改已有系统, 符合“开闭原则”。
缺点:
-
规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂 的接口。
-
增加了系统的抽象性和理解难度。
适用场景:
系统中有多个产品族,而系统一次只可能消费其中一族产品。而这一族产品中每种产品又需要具有不同的创建方法
结构图:
实例:
拓展:
利用简单工厂模式优化抽象工厂
package 抽象工厂模式;
public class DataAccess {
private static String db="Sqlserver";
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 IDepartment CreateDepartment() {
IDepartment result =null;
switch(db){
case"Sqlserver":
result=new SqlserverDepartment();
break;
case"Access":
result=new AccessDepartment();
break;
}
return result;
}
}
利用反射+抽象工厂 进行优化
package 抽象工厂模式;
//不在再使用switch-case语句
public class DataAccess1 {
private static String AssemblyName="抽象工厂模式";
private static String db="Sqlserver";
public static IUser CreateUser() throws InstantiationException, IllegalAccessException, ClassNotFoundException{
String className=AssemblyName+"."+db+"User";
return (IUser)Class.forName(className).newInstance();
}
public static IDepartment CreateDepartment() throws InstantiationException, IllegalAccessException, ClassNotFoundException{
String className=AssemblyName+"."+db+"Department";
return (IDepartment)Class.forName(className).newInstance();
}
}