设计模式之简单工厂模式

来源:互联网 发布:简单网络协议实现 编辑:程序博客网 时间:2024/06/02 02:03

关于设计模式的学习笔记,教材:《设计模式的艺术之道》 刘伟 著

简单工厂模式是工厂模式的“小弟”,而工厂模式有一个“大哥”——抽象工厂模式。
Simple Factory Pattern: 定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常具有共同的父类。因为简单工厂模式中用于创建实例的方法是静态方法,因此该模式亦称为静态工厂方法模式,属于类创建型模式。

例:
使用简单工厂模式设计一个可以创建不同几何形状(如圆形、方形和三角形等)的绘图工具,每个几何图形都具有绘制和擦除两个方法,要求在绘制不支持的几何图形时,抛出一个UnSupportedShapeException。

interface Shape {    void draw() throws UnSupportedShapeException;    void erase();}public class Circle implements Shape {    @Override    public void draw() {        System.out.println("圆形绘制");    }    @Override    public void erase() {        System.out.println("圆形擦除");    }    public Circle(){        System.out.println("圆形创建");    }}public class Rect implements Shape {    @Override    public void draw()  {        System.out.println("方形绘制");    }    @Override    public void erase() {        System.out.println("方形擦除");    }    public Rect(){        System.out.println("方形创建");    }}public class Triangle implements Shape {    @Override    public void draw() {        System.out.println("三角形绘制");    }    @Override    public void erase() {        System.out.println("三角形擦除");    }    public Triangle(){        System.out.println("三角形创建");    }}public class UnSupportedShapeException extends Exception {    public UnSupportedShapeException(String msg){        super(msg);    }}public class ErrorShape implements Shape {    private String type=null;    @Override    public void draw() throws UnSupportedShapeException {            throw new UnSupportedShapeException("不支持 "+type+" 这种图形");    }    @Override    public void erase() {    }    public ErrorShape(String msg){        type=msg;    }}public class SimpleFactory{    public static Shape getShape(String type) throws UnSupportedShapeException {        Shape shape=null;        String string=type.toLowerCase();        switch (string){            case "circle":                shape=new Circle();                break;            case "rectangle":                shape=new Rect();                break;            case "triangle":                shape=new Triangle();                break;            default:                shape=new ErrorShape(string);                break;        }        return shape;    }    public static void main(String[] args){        try {            Shape a=getShape("triangle");            a.draw();            a.erase();            Shape b = getShape("cirCle");            b.draw();            b.erase();            Shape c=getShape("rectangle");            c.draw();            c.erase();            Shape d=getShape("olard");            d.draw();            /*            三角形创建            三角形绘制            三角形擦除            圆形创建            圆形绘制            圆形擦除            方形创建            方形绘制            方形擦除        designPattern.SimpleFactory.UnSupportedShapeException: 不支持 olard 这种图形                ...            */        }catch (Exception e){            e.printStackTrace();        }    }}

但是,在使用getShape("type")创建具体的Shape对象时,每更换一个Shape对象都要修改参数,要重新编译,违反了开闭原则。
这时可以把参数存储在XML格式的配置文件中,如config.xml

<?xml version="1.0"?><config>    <shapeType>triangle</shapeType>    </config>

再通过一个工具类XMLUtil来读取配置文件中的字符串参数:

public class XMLUtil {    public static String getShapeType() {        try {            //创建文档对象            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();            DocumentBuilder builder = builderFactory.newDocumentBuilder();            Document document = builder.parse(new File("config.xml"));            NodeList nodeList = document.getElementsByTagName("shapeType");            Node node = nodeList.item(0).getFirstChild();            String shapeType = node.getNodeValue().trim();            return shapeType;        } catch (Exception e) {            e.printStackTrace();            return null;        }    }}

使用时略作修改

 public static void main(String[] args){        try {            Shape a;            String type=XMLUtil.getShapeType();            a=getShape(type);            a.draw();            a.erase();        }catch (Exception e){            e.printStackTrace();        }    }

但是,当要添加新的具体图形类时,依然免不了要修改SimpleFactory的getShape方法。这如何解决呢?
这会在下一个设计模式——工厂方法模式中使用reflect(反射)解决。

优缺点
优点

  1. 实现了对象创建和使用的分离
  2. 减少使用者记忆量,比如rectangle类,有两个构造方法,分别是构造正方形和长方形的,我们不需要去记住其构造方法名和构造列表,只需要记住给getShape传什么参数即可
  3. 通过引入配置文件,可以在不修改客户端代码的情况下更换新的具体产品类,提高系统的灵活性。(如何要添加新的产品,要修改工厂类)

缺点
1. 工厂类包含了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都收到影响
2. 增加类的个数,增加系统复杂度和理解程度
3. 系统拓展困难,添加新产品必修修改工厂类的逻辑;具体产品类较多时,工厂逻辑过于复杂,不利于系统的拓展和维护
4. 简单工厂模式使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构?

适用场景

  1. 工厂类负责创建的对象较少
  2. 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
0 0
原创粉丝点击