简单工厂模式
简单工厂模式是指由一个工厂对象决定创建哪一种产品类的实例。
以课程为例,假如目前某学院开设Java架构、大数据、人工智能等课程,通常的写法:
public interface ICourse {
/** 录制视频 */
public void record();
}
public class JavaCourse implements ICourse {
@Override
public void record() {
System.out.println("录制Java视频");
}
}
public class PythonCourse implements ICourse {
@Override
public void record() {
System.out.println("录制Python视频");
}
}
public class Test {
public static void main(String[] args) {
ICourse javaCourse = new JavaCourse();
javaCourse.record();
ICourse pythonCourse = new PythonCourse();
pythonCourse.record();
}
}
Test类需要依赖JavaCourse和PythonCourse,如果还有别的课程,那么Test还将继续依赖,违背了迪米特原则。
现在用简单工厂模式进行优化,首先创建一个CourseFactory工厂类。
public class CourseFactory {
public ICourse create(String name) {
if("java".equals(name)) {
return new JavaCourse();
} else if("python".equals(name)) {
return new PythonCourse();
} else {
return null;
}
}
}
public class SimpleFactoryTest {
public static void main(String[] args) {
CourseFactory courseFactory = new CourseFactory();
courseFactory.create("java");
courseFactory.create("python");
}
}
客户端调用时变简单了,但是工厂类的设计不符合开闭原则,因为如果要增加前端课程,那么工厂的create()方法就要修改代码,继续优化。
public class CourseFactory {
public ICourse create(String className) {
if(!(null == className || "".equals(className))) {
try {
return (ICourse) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
public class SimpleFactoryTest {
public static void main(String[] args) {
CourseFactory courseFactory = new CourseFactory();
ICourse course = courseFactory.create("cn.itdjn.ch2.ch2_2.ch2_2_2.JavaCourse");
course.record();
}
}
现在不需要修改CourseFactory中的代码,但方法参数是字符串,可控性有待提升,而且还需要强制类型转换,继续优化。
public class CourseFactory {
public ICourse create(Class<? extends ICourse> clazz) {
try {
if(null != clazz) {
return clazz.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public class SimpleFactoryTest {
public static void main(String[] args) {
CourseFactory courseFactory = new CourseFactory();
ICourse course = courseFactory.create(JavaCourse.class);
course.record();
}
}
工厂方法模式
定义一个创建对象的接口,让实现这个接口的类决定实例化哪个类,工厂方法模型让类的实例化推迟到子类中进行。简单工厂模式中随着产品链的丰富,可能会出现每个课程创建逻辑上的区别,这个时候单一的简单工厂模式就会变得不易于维护。我们需要根据单一职责原则将职能区分,专人干专事。此时Java课程由Java工厂创建,Python课程由Python工厂创建。
public interface ICourseFactory {
ICourse create();
}
public class JavaCourseFactory implements ICourseFactory {
@Override
public ICourse create() {
return new JavaCourse();
}
}
public class PythonCourseFactory implements ICourseFactory {
@Override
public ICourse create() {
return new PythonCourse();
}
}
public class Test {
public static void main(String[] args) {
ICourseFactory factory = new PythonCourseFactory();
ICourse course = factory.create();
course.record();
factory = new JavaCourseFactory();
course = factory.create();
course.record();
}
}
抽象工厂模式
先解释什么是产品族,上图第一行假设都是美的公司生产的家用电器,那么正方形表示美的冰箱,圆形表示美的空调,菱形表示美的热水器。那么第二行可能就是格力冰箱、格力空调、格力热水器,依次类推。
在解释什么产品等级结构,上图第一列都是冰箱,第二列都是空调,第三列都是热水器,但是每行属于不同的厂家制造的。那厂家不同,工厂也就不一样,所以延伸出下面的图形。
由上图可以看出,第一行的美的产品是由美的工厂生产的,第二行的格力产品是由格力工厂生产的,这两个工厂是不同的具体工厂。
以上面的电器为例,假如现在要制造冰箱、空调、洗衣机,那么这三个产品是三个不同的产品等级结构。
冰箱、空调、洗衣机接口如下:
/**
* 空调
*/
public interface IAirConditioner {
void refrigeration(); // 制冷
}
/**
* 冰箱
*/
public interface IRefrigerator {
void coldStorage(); // 冷藏
}
/**
* 洗衣机
*/
public interface IWashingMachine {
void washClothes(); // 洗衣服
}
抽象工厂类:
/**
* 抽象工厂
*/
public interface HomeApplianceFactory {
IRefrigerator createRefrigerator();
IAirConditioner createAirConditioner();
IWashingMachine createWashingMachine();
}
具体不同厂家的冰箱、空调、洗衣机:
/**
* 美的空调
*/
public class BeautifulAirConditioner implements IAirConditioner {
@Override
public void refrigeration() {
System.out.println("美的空调可以制冷");
}
}
/**
* 美的冰箱
*/
public class BeautifulRefrigerator implements IRefrigerator {
@Override
public void coldStorage() {
System.out.println("美的冰箱冷藏食物");
}
}
/**
* 美的洗衣机
*/
public class BeautifulWashingMachine implements IWashingMachine {
@Override
public void washClothes() {
System.out.println("美的洗衣机可以洗衣服");
}
}
/**
* 格力空调
*/
public class GreeAirConditioner implements IAirConditioner {
@Override
public void refrigeration() {
System.out.println("格力空调可以制冷");
}
}
/**
* 格力冰箱
*/
public class GreeRefrigerator implements IRefrigerator {
@Override
public void coldStorage() {
System.out.println("格力冰箱冷藏食物");
}
}
/**
* 格力洗衣机
*/
public class GreeWashingMachine implements IWashingMachine {
@Override
public void washClothes() {
System.out.println("格力洗衣机可以洗衣服");
}
}
具体不同厂家的工厂类:
/**
* 美的工厂
*/
public class BeautifulFactory implements HomeApplianceFactory {
@Override
public IRefrigerator createRefrigerator() {
return new BeautifulRefrigerator();
}
@Override
public IAirConditioner createAirConditioner() {
return new BeautifulAirConditioner();
}
@Override
public IWashingMachine createWashingMachine() {
return new BeautifulWashingMachine();
}
}
/**
* 格力工厂
*/
public class GreeFactory implements HomeApplianceFactory{
@Override
public IRefrigerator createRefrigerator() {
return new GreeRefrigerator();
}
@Override
public IAirConditioner createAirConditioner() {
return new GreeAirConditioner();
}
@Override
public IWashingMachine createWashingMachine() {
return new GreeWashingMachine();
}
}
测试类:
public class Test {
public static void main(String[] args) {
HomeApplianceFactory factory = new BeautifulFactory();
factory.createAirConditioner().refrigeration();
factory.createRefrigerator().coldStorage();
factory.createWashingMachine().washClothes();
factory = new GreeFactory();
factory.createAirConditioner().refrigeration();
factory.createRefrigerator().coldStorage();
factory.createWashingMachine().washClothes();
}
}
上述完整的描述了两个产品族,但是如果继续扩展产品等级,比如增加电风扇,那代码从抽象工厂到具体工厂都要调整,这违背了开闭原则,因此抽象工厂也是有缺点的,但是是可接受的,只要不是过于频繁的升级。