工厂模式就是自己不去实例化对象,而使用对象工厂去实例化对象,大致分3种:简单工厂模式、工厂模式、抽象工厂模式
先定义几个类:Person
类,人这个类是个父类,而人分很多种人,这里举例子有Student
类和Teacher
类继承了Person
类。
简单工厂模式
public class PersonFactory {
public static Person createPerson(String type) {
Person person = null;
switch (type) {
case "student":
person = new Student();
break;
case "teacher":
person = new Teacher();
break;
}
return person;
}
}
定义一个人类工厂,工厂有个静态方法根据不同类型的参数来造不同的人:
public static void main(String[] args) {
Student student = (Student) PersonFactory.createPerson("student");
System.out.println(student.toString()); // Student [grade=null, classes=null, school=null,name=null]
}
这是最简单的工厂模式,在业务简单中他的确比较好使。但是他有个问题就是工厂类里面的设计不符合“开放-封闭”原则。如果业务有改动,比如要加个Master
校长类,就得去改这个类,每次修改业务都要去改工厂类,这是不合适的。所以在简单工厂模式的基础上有个工厂模式。
工厂模式
为了不去改工厂类中的方法,所以把工厂类做成一个接口,接口中定义工厂方法:
public interface PersonFactory {
public Person createPerson();
}
然后根据工厂类中的各个条件分支分别去写各种工厂接口的实现类,创建学生的工厂类StudentFactory
:
public class StudentFactory implements PersonFactory{
public Student createPerson(){
return new Student();
}
}
创建老师的工厂类TeacherFactory
:
public class TeacherFactory implements PersonFactory{
public Teacher createPerson(){
return new Teacher();
}
}
如果再要加创建校长的工厂类的话只需要实现PersonFactory
接口,然后按照其逻辑来实现createPerson()
方法即可。
调用的地方 直接调用相应的实现类中的方法就可以创建相应的对象了:
public static void main(String[] args) {
PersonFactory factory = new StudentFactory();
Person student = factory.createPerson();
System.out.println(student.toString()); // Student [grade=null, classes=null, school=null,name=null]
}
然而这样也不是完全就没有任何问题的,相像一下如果要创建世界上所有职业类型的人类,那就要去写“司机”、“前台”、“老板”…无数个工厂类了,这肯定是不行的,所以代码可以再提练一下:
public class PersonFactory {
@SuppressWarnings("unchecked")
public <T extends Person> T createPerson(Class<T> clazz) {
Person p = null;
try {
p = (Person) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return (T) p;
}
}
利用反射来动态的传一个类类型过来,然后再根据类类型来创建对应的对象,这样就不用去写各种类型的实现工厂类了。测试如下:
public class PersonFactoryTest {
public static void main(String[] args) {
PersonFactory personFactory = new PersonFactory();
Student student = personFactory.createPerson(Student.class);
System.out.println(student.toString()); // // Student [grade=null, classes=null, school=null,name=null]
}
}
这样就不用再去一个个的写工厂类了,只用写继承Person
类的实体类就行了。
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。抽象工厂模式意图提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。主要解决接口选择的问题,系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
接着上面的代码举例子,这里先定义一个“系列产品”:StudentFemale
、StudentMale
、TeacherFemale
、TeacherMale
分别是女学生、男学生、女老师、男教师。他们可以抽象成2类,男性、女性:
// 男性产品抽象接口
public interface IMale {
void printName();
}
// 女性产品抽象接口
public interface IFemale {
void printName();
}
每个产品分别实现对应的抽象接口,此处只贴一个“产品”,男老师的代码,其他几个的代码都是一样的:
public class TeacherMale implements IMale {
private String name;
@Override
public void printName() {
System.out.println("TeacherMale..."+this.name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TeacherMale(String name) {
super();
this.name = name;
System.out.println("TeacherMale...constructor");
}
}
“产品”定义好了,再定义一下超级工厂PersonFactory
接口:
public interface PersonFactory {
IMale createMale(String name);
IFemale createFemale(String name);
}
这个工厂里面定义2个接口,创建男性和创建女性,超级工厂定义好了后,一般的工厂再来实现这个超级工厂:
创建学生的工厂StudentFactory
类:
public class StudentFactory implements PersonFactory {
@Override
public IMale createMale(String name) {
return new StudentMale(name);
}
@Override
public IFemale createFemale(String name) {
return new StudentFemale(name);
}
}
创建老师的工厂TeacherFactory
类:
public class TeacherFactory implements PersonFactory {
@Override
public IMale createMale(String name) {
return new TeacherMale(name);
}
@Override
public IFemale createFemale(String name) {
return new TeacherFemale(name);
}
}
至此抽象工厂模式就写好了,看测试:
public class MainTest {
public static void main(String[] args) {
StudentFactory sf = new StudentFactory();
TeacherFactory tf = new TeacherFactory();
IFemale studnetFemale = sf.createFemale("女学生");
IMale studnetMale = sf.createMale("男学生");
IFemale teacherFemale = tf.createFemale("女教师");
IMale teacherMale = tf.createMale("男教师");
studnetFemale.printName();
studnetMale.printName();
teacherFemale.printName();
teacherMale.printName();
}
}
测试输出:
StudentFemale...constructor
StudentMale...constructor
TeacherFemale...constructor
TeacherMale...constructor
StudentFemale...女 学生
StudentMale...男 学生
TeacherFemale...女 教师
TeacherMale...男 教师
最后再画个草图示意一下: