工厂模式属于创建型模式,一共有三种,分别是:简单工厂模式,方法工厂模式以及抽象工厂模式。
1.简单工厂模式
定义:
简单工厂模式(Simple Factory Pattern)又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
适用场景:
- 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
UML图:
代码:
先定义一个抽象类或接口作为基类,这里采用接口的形式
public interface Shape {
public void create();
}
然后分别创建三个子类来实现这个接口:
圆形:
public class Circle implements Shape {
@Override
public void create() {
System.out.println("创建圆形");
}
}
长方形:
public class Rectangle implements Shape {
@Override
public void create() {
System.out.println("创建长方形");
}
}
正方形:
public class Square implements Shape {
@Override
public void create() {
System.out.println("创建正方形");
}
}
简单工厂类:
public class SimpleFactory {
public static Shape createShape(String shapeName){
Shape shape = null;
if (shapeName.equals("rectangle")){
shape = new Rectangle();
}else if (shapeName.equals("square")){
shape = new Square();
}else if (shapeName.equals("circle")){
shape = new Circle();
}
return shape;
}
}
测试代码:
public class Test {
public static void main(String[] args) {
Shape circle = SimpleFactory.createShape("circle");
circle.create();
Shape rectangle = SimpleFactory.createShape("rectangle");
rectangle.create();
Shape square = SimpleFactory.createShape("square");
square.create();
}
}
打印输出:
创建圆形
创建长方形
创建正方形
优缺点分析:
优点:
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
缺点:
- 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
- 简单工厂模式由于使用了静态工厂方法,导致了静态方法无法被继承
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
2.工厂方法模式
定义:
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
适用场景:
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类。
- 客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
UML图
还是以上述创建正方形、长方形和圆形为例,区别在于本次不是使用一个简单工厂类去创建所有的形状实例,而是定义一个工厂接口,让子类决定实例化哪一个类。
代码:
上述的Shape、Circle、Rectangle、Square类的代码都一样我就不一一贴了。看有变化的:
工厂接口:
public interface MethodFactory {
public Shape getShape();
}
三个实现类:
CircleFactory
public class CircleFactory implements MethodFactory {
@Override
public Shape getShape() {
return new Circle();
}
}
RectangleFactory
public class RectangleFactory implements MethodFactory {
@Override
public Shape getShape() {
return new Rectangle();
}
}
SquareFactory
public class SquareFactory implements MethodFactory{
@Override
public Shape getShape() {
return new Square();
}
}
测试代码类:
public class Test {
public static void main(String[] args) {
//创建圆形
MethodFactory methodFactory = new CircleFactory();
Circle circle = (Circle) methodFactory.getShape();
circle.create();
//创建长方形
MethodFactory methodFactory1 = new RectangleFactory();
Rectangle rectangle = (Rectangle) methodFactory1.getShape();
rectangle.create();
//创建正方形
MethodFactory methodFactory2 = new SquareFactory();
Square square = (Square) methodFactory2.getShape();
square.create();
}
}
打印输出:
创建圆形
创建长方形
创建正方形
优缺点分析:
优点:
- 在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
缺点:
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 无法体现产品之间的关系,如果有两个不同的产品需要创建,就需要两个不同的工厂类,即使这两个产品有某钟必要的联系,也还是需要两个不同的工厂类。
3.抽象工厂模式
定义:
上面我们知道工厂方法模式是具体的工厂生产具体的产品,每一个具体工厂负责一个具体产品。但是有时候我们需要一个工厂类提供多个产品,而不是单一的产品对象,因此就引出了抽象工厂模式:
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
适用场景:
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。
- 生成不同操作系统的程序。
UML图:
案例:
以上面的UML图为例,有一个用户想买一台海尔的电冰箱用和一台长虹的电视机来看,我们定义了两个接口:Tv和Fridge,Tv下面有长虹电视和海尔电视的实现类,Fridge下面有海尔电冰箱和长虹电冰箱的实现,而负责生产HaierTv和HaierFridge的是HaierFactory,负责生产ChangHongTv 和ChangHongFridge的是ChangHongFactory,而这两个工厂是抽象类(接口)AbstractFactory的实现类。上代码:
Tv
public interface Tv {
public void watch();
}
Fridge
public interface Fridge {
public void open();
}
ChangHongTv
public class ChanghongTv implements Tv {
@Override
public void watch() {
System.out.println("观看长虹电视机");
}
}
HaierTv
public class HaierTv implements Tv {
@Override
public void watch() {
System.out.println("观看海尔电视机");
}
}
ChanghongFridge
public class ChanghongFridge implements Fridge {
@Override
public void open() {
System.out.println("打开长虹电冰箱");
}
}
HaierFridge
public class HaierFridge implements Fridge {
@Override
public void open() {
System.out.println("打开海尔电冰箱");
}
}
AbstractFactory
public interface AbstractFactory {
public Tv getTv();
public Fridge getFridge();
}
ChanghongFactory
public class ChanghongFactory implements AbstractFactory{
@Override
public Tv getTv() {
return new ChanghongTv();
}
@Override
public Fridge getFridge() {
return new ChanghongFridge();
}
}
HaierFactory
public class HaierFactory implements AbstractFactory{
@Override
public Tv getTv() {
return new HaierTv();
}
@Override
public Fridge getFridge() {
return new HaierFridge();
}
}
测试类:
public class Test {
public static void main(String[] args) {
AbstractFactory factory = new ChanghongFactory();
ChanghongTv changhongTv = (ChanghongTv) factory.getTv();
changhongTv.watch();
AbstractFactory factory1 = new HaierFactory();
HaierFridge haierFridge = (HaierFridge) factory1.getFridge();
haierFridge.open();
}
}
打印输出:
观看长虹电视机
打开海尔电冰箱
优缺点分析:
优点:当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象
缺点:在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品
4.小结
工厂模式的意义: 将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦,从而提高项目的扩展性和维护性
工厂模式的三种方式: 简单工厂模式、工厂方法模式、抽象工厂模式
注意:
- 创建实例对象时,不要直接new该实例类,而是把这个动作放在一个工厂方法里面并返回
- 不要让类集成具体类,而是继承抽象类或是接口
- 不要覆盖基类中已经实现的方法