通过实例说设计模式——简单工厂模式

本文我们通过实例的方式来简单描述一下简单工厂模式的由来及其作用,话说我们现在需要开发一个图形界面工具,然后将这个工具提供给一个客户去使用,系统初期我们只需要画一个圆(Circle)和一个三角形(Triangle)即可。那么我们的工具就按照如下的方式设计。

public class Shape {
    public void draw(String type) {
        if(type.equals("circle")) {
            System.out.println("画一个圆");
        }else if(type.equals("triangle")) {
            System.out.println("画一个三角形");
        }
    }
}

当客户使用时就可以直接按照如下的方式去使用

public class TestDemo {
    public static void main(String[] args) {
        Shape shape = new Shape();
        shape.draw("circle");
        shape.draw("triangle");
    }
}

过一段时间之后,我们发现我们的工具中需要增加长方形(Rectangle)、正方形(Square)等很多其他的图形。那么这时我们就需要修改我们的Shape类。那么我们的Shape类会变成如下的样子。

public class Shape {
    public void draw(String type) {
        if(type.equals("circle")) {
            System.out.println("画一个圆");
        }else if(type.equals("triangle")) {
            System.out.println("画一个三角形");
        }else if(type.equals("...")){
//长方形
  }else if(type.equals("...")){
//正方形
   }
    }
}

那么如果按照这样的设计将会造成如下的一些缺陷。

  1. 我们的Shape类中的代码会因为图形的不断增多,会出现过多的if{}else{}代码块,整个类的代码会非常的多,非常不容易阅读。

  2. Shape类的职责过重,它负责初始化所有的图形对象,将所有的图形初始化代码放在一个类中,违反“单一职责(一个类或者一个方法只负责执行或完成一个任务)”原则,非常不利于重构及维护。

  3. 当需要增加新的图形时,需要修改Shape的源代码,违背“开闭原则(开:开放拓展;闭:不能修改原来的代码)”;

  4. 客户在使用的时候,需要通过new关键字来直接创建Shape对象,Shape与客户端的耦合度非常之高;

面对上面的一些缺陷呢,接下来我们慢慢开始一个一个的解决。

首先,对于图形的不断增多,会增加Shape类的代码量、同时不同的图形,其绘制的方法不一样,即职责不一样;所以我们将不同的图形放在不同的类中去实现。

public class Circle {
    public void draw() {
        System.out.println("绘制圆形");
    }
}
public class Triangle {
    public void draw() {
        System.out.println("绘制三角形");
    }
}
//.. ...

客户端调用时按照如下方式去调用

public class TestDemo {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.draw();

        Triangle triangle = new Triangle();
        triangle.draw();
    }
}

通过上面的改造我们发现,我们遵循了“单一职责原则”将图形的实现划分到了不同的图形类中,但是这种实现中,客户使用时需要知道所有的图形类,并且需要通过new关键字来实例化具体的图形,我们的工具中的具体实现类与客户程序的耦合度非常的高。接下来我们再做一些改造,让客户的使用与具体的图形实现类解耦。
首先我们声明一个图形(Shape)接口如下:

public interface Shape {
    /**
     * 绘制图形
     */
    void draw();
    /**
     * 擦除图形
     */
    void erase();
}

具体图形类实现该接口,示例如下

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }

    @Override
    public void erase() {
        System.out.println("擦除圆形");
    }
}

public class Triangle implements Shape {

    @Override
    public void draw() {
        // TODO Auto-generated method stub
        System.out.println("绘制三角形");
    }

    @Override
    public void erase() {
        // TODO Auto-generated method stub
        System.out.println("擦除三角形");
    }
}

要让客户端与具体的实现类之间解耦,那么我们就需要重新创建一个类,通过这个类来获取具体的图形实例,然后将图形对象提供给客户端使用即可,这个类我们就称之为简单工厂。

public class ShapeFactory {
    public static Shape getShape(String type) {
        if(type.equals("triangle")) {
            return new Triangle();
        }else if(type.equals("circle")) {
            return new Circle(10);
        } else {
            System.out.println("不支持的类型");
            return null;
        }
    }
}

客户端在使用我们的工具时,不需要知道具体的图形类实现,只需要知道我们提供的图形工具中有一个工厂类ShapeFactory,并且通过一些固定的参数能够获取到想要的图形即可。

public class TestDemo {
    public static void main(String[] args) {
        Shape shape = ShapeFactory.getShape("triangle");
        shape.draw();
        shape.erase();

        shape=ShapeFactory.getShape("circle");
        shape.draw();
        shape.erase();
    }
}

这样我们就实现了一个简单工厂,通过简单工厂,我们实现了客户端与具体实现类的解耦,同时具体类的实现也遵循了“单一职责原则”,同时提高了代码的可读性、降低了代码的复杂度;

  • 简单工厂模式的定义:定义一个工厂类, 它可以根据参数的不同返回不同类的实例, 被创建的实例通常都具有共同的父类或者实现了同一个接口。因为在简单工厂模式中用于创建实例的方法是静态(static)方法, 因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式, 它属于类创建型模式。

  • 简单工厂模式的要点:当你需要什么, 只需要传入一个正确的参数, 就可以获取你所需
    要的对象, 而无须知道其创建细节。

在简单工厂模式结构图中包含如下几个角色

  • Factory( 工厂角色) : 工厂角色即工厂类(以上示例中的ShapeFactory), 它是简单工厂模式的核心, 负责实现创建所有产品实例的内部逻辑; 工厂类可以被外界直接调用, 创建所需的产品对象; 在工厂类中提供了静态的工厂方法factoryMethod(), 它的返回类型为具体实现类型的公共接口(上例中的Shape接口)或父类。

  • 具体类型的公共接口(Shape)或父类:他是工厂所创建的所有对象的父类,封装了所有被创建对象的公共方法,该角色的引入大大提高了系统的灵活性,使得工厂类中只需要定义一个通用的工厂方法,因为所有创建的具体对象都是该角色的子类对象,为客户端和具体实现类之间的解耦提供了很大的好处。

  • 具体实现类(如Circle、Triangle ):它是工厂类创建的目标,所有被创建的对象都充当这个角色的某个具体实现类。具体实现类都实现了一个公共的接口或者都继承了一个公共的父类,它们需要实现接口或父类中声明的抽象方法。

小结

简单工厂模式提供了专门的工厂类用于创建对象, 将对象的创建和对象的使用分离开, 它作为一种最简单的工厂模式在软件开发中得到了较为广泛的应用。

简单工厂模式的优点

  • 工厂类包含一些逻辑判断,可以决定在什么时候创建哪一个具体类的实例。

  • 由于简单工厂模式实现了对象的创建和使用分离,所以当增加具体类时,只需要在工厂类中增加对应的创建逻辑,不会影响客户端对工具的使用。

  • 客户端无需知道所创建的具体类,只需要知道具体的类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度上减少使用者的记忆量。

简单工厂模式的缺点

  • 具体类实例的创建都放在单一的工厂类中,工厂类的职责过重;

  • 当具体类变得越来越多时,工厂类的代码量会越来越庞大,不利于阅读和维护;

  • 当增加新的具体类时,都需要修改工厂类将新的具体类的实例创建方式在工厂类中实现,不符合“开闭原则”;

  • 简单工厂模式由于使用了静态工厂方法, 造成工厂角色无法形成基于继承的等级结构。

适用场景

  • 工厂类负责创建的对象比较少, 由于创建的对象较少, 不会造成工厂方法中的业务逻辑太过复杂。

  • 客户端只知道传入工厂类的参数, 对于如何创建对象并不关心。

参考:https://blog.csdn.net/lovelion/article/details/9300337

你可能感兴趣的:(Java,设计模式)