简单工厂模式
任何可以产生对象的方法或类,都可以称之为工厂。单例也可以成为一种工厂。为什么可以new对象,还需要工厂?因为可以灵活控制生产过程。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
比如需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。
简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,
但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,
而且产品较多时,工厂方法代码逻辑将会非常复杂。
比如像下面的代码,我想增加一个画平行四边形的,那么则有需要建一个类去实现Shape接口。扩展性差。
创建一个接口
形状类,里面有一个画画的方法
public interface Shape {
void draw();
}
创建实现接口的实体类。
矩形类,实现了形状类,重写了画画方法,画出了一个矩形
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画出矩形::draw() method.");
}
}
方形类,实现了形状类,重写了画画方法,画出了一个方形
public class Square implements Shape {
@Override
public void draw() {
System.out.println("画出方形::draw() method.");
}
}
圆形类,实现了形状类,重写了画画方法,画出了一个圆形
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("画出圆形::draw() method.");
}
}
创建一个工厂,生成基于给定信息的实体类的对象。
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
//根据传入的形状类型,返回对应的类
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
使用该工厂,通过传递类型信息来获取实体类的对象。
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//获取 Circle 的对象,并调用它的 draw 方法
Shape shape1 = shapeFactory.getShape("CIRCLE");
//调用 Circle 的 draw 方法
shape1.draw();
//获取 Rectangle 的对象,并调用它的 draw 方法
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取 Square 的对象,并调用它的 draw 方法
Shape shape3 = shapeFactory.getShape("SQUARE");
//调用 Square 的 draw 方法
shape3.draw();
}
}
工厂方法模式
是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,
则不能正确创建对象,而工厂方法模式是提供多个工厂方法,分别创建对象。
将上面的ShapeFactory形状工厂类,稍微改动一下。
public class ShapeFactory {
//直接返回圆形类
public Shape getCircleShape(){
return new Circle();
}
//直接返回矩形类
public Shape getRectangleShape(){
return new Rectangle();
}
//直接返回方形类
public Shape getSquareShape(){
return new Square();
}
}
//测试
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
Shape circle = shapeFactory.getCircleShape();
//调用 Circle 的 draw 方法
circle.draw();
}
}
静态工厂方法模式
将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
public class ShapeFactory {
//直接返回圆形类
public static Shape getCircleShape(){
return new Circle();
}
//直接返回矩形类
public static Shape getRectangleShape(){
return new Rectangle();
}
//直接返回方形类
public static Shape getSquareShape(){
return new Square();
}
}
//测试
public class FactoryPatternDemo {
public static void main(String[] args) {
Shape circle = ShapeFactory.getCircleShape();
//调用 Circle 的 draw 方法
circle.draw();
}
}
总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
抽象工厂模式
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,
必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?
就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,
不需要修改之前的代码。
创建一个接口
形状类,里面有一个画画的方法
public interface Shape {
void draw();
}
创建实现接口的实体类。
矩形类,实现了形状类,重写了画画方法,画出了一个矩形
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画出矩形::draw() method.");
}
}
方形类,实现了形状类,重写了画画方法,画出了一个方形
public class Square implements Shape {
@Override
public void draw() {
System.out.println("画出方形::draw() method.");
}
}
圆形类,实现了形状类,重写了画画方法,画出了一个圆形
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("画出圆形::draw() method.");
}
}
再创建一个接口,或者抽象类,这里以接口为例
public interface ShapeFactory {
public Shape shape();
}
创建对应的工厂类
实现上面的工厂类,并且重写方法
public class CircleFactory implements ShapeFactory{
@Override
public Shape shape(){
return new Circle();
}
}
public class RectangleFactory implements ShapeFactory{
@Override
public Shape shape(){
return new Rectangle();
}
}
public class SquareFactory implements ShapeFactory{
@Override
public Shape shape(){
return new Square();
}
}
其实这个模式的好处就是,如果你现在想增加一个功能:比如画任意形状,则只需做一个实现类,实现Shape接口,同时做一个工厂类,实现ShapeFactory接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!