设计模式之反射机制下的工厂模式,写完具体类马上就能用

版权声明:之江学院 黄日超 https://blog.csdn.net/weixin_41474319/article/details/82974103

先修知识

多态

  1. 接口与父类可作返回类型,引用声明类型.
  2. 实现类与继承类可作构造类型,反射强制转换类型,反射(子类.class)获取元类型

利用反射拓展工厂生产能力

反射一定是用在通用的场景,故利用反射机制时不应该出现具体类的名字,最多用到接口或抽象类.

  1. 定义输入参数:public static Object getClass(Class<?extends Shape> clazz)//定义元类型Class的范围,必须满足是Shape的子类

ps:如何输入(Class clazz)元类型?
通过类的元类型 Class clazz=Object.class 或对象的元类型 Class clazz.=obj.getClass().

  1. 获取元类型对象对应的类型名:clazz.getName()
  2. 根据类名加载对应的类,运行其中的静态方法:Class.forName(clazz.getName())
  3. 加载完后创建对应的实例:Object obj = Class.forNmae(clazz.getName()).getInstance();
  4. return obj;

应用反射工厂类时人们一般都写好了具体类,人们是知道具体类名的

  1. 利用反射机制获取对应类的类对象:Object obj = ShapeFactory.getClass(Square.class)
  2. 用具体类强制转换:Square square = (Square) ShapeFactory.getClass(Square.class);
  3. 完美实现子类的拓展,且不用修改工厂类的源码

工厂模式

Factory创建对象,用于不同条件创建不同实例时.比如用三大协议连接服务器.

优点:

想创建一个对象只要知道名称即可.想增加一个产品线,拓展一个工厂类和具体类即可.无需知道具体实现

缺点:

每增加一个产品线,必须新增一个具体类(实验室)和对象实现工厂.

创建接口

public interface Shape{
    void draw;
}

接口的具体类

public class Rectangle implements Shape{
    @Override
    public void draw(){
        System.out.println("InsideRectangle::draw() method.");
    }
}
Square
Circle

单一工厂

依据输入的信息,生产对应的产品

public class ShapeFactory{
    public Shape getShape(String shapeType){
        if(shapeType == null){
            return null;
        }
        if(shapeType.equalsIgnoreCase("CIRCLE")){
            return new Circle();
        }else if(shapeType.equalsIgnoreCase("Square")){
            return new Square();
        }else if(shapeType.equalsIgnoreCase("Rectangle")){
            return new Rectangle();
        }
        return null;//若有输入但信息错误,则返回null

    }
}

使用工厂类,生成对应产品,并访问对应的功能

public class FactoryPatternDemo{
    public static void main(String[] args){
        ShapeFactory shapeFactory = new ShapeFactory();
        Shape shape1 = shapeFactory.getShape("Circle");
        shape1.draw();
        Shape shape2 = shapeFactory.getShape("Rectangle");
        shape2.draw();
        Shape shape3 = shapeFactory.getShape("Square");
        shape3.draw();
    }
}

采用反射机制重构工厂类

摆脱必须在源码中 if(具体类) return new 具体类的尴尬

尴尬是因为源码中写了多少就只能用多少,想用新产品必须修改源码,非常麻烦

public class ShapeFactory{
    public static Object getClass(Class<? extends Shape> clazz){//限制必须是Shape的子类
       Object obj = null;//万能多态对象
       try{
           obj = Class.forName(clazz.getNmae()).newInstance();
       }catch(ClassNotFoundException e){
           e.printStackTrace();
       }
       return obj;
    }
}

利用JDK9特性的改进版

Class.forName(clazz.getName())等价于clazz.getConstructor

使用时强制转换一下即可

public class FactoryPatternDemo{
    public static void main(String[] args){
        Rectangle rect = (Rectangle)ShapeFactory.getClass(Rectangle.class);
        rect.draw();
        Square square = ShapeFactory.getClass(Rectangle.class);
        square.draw();
    }
}

工厂模式总结

实现功能方法
在工厂的创建方法中被用来new实例
输入\类名.class\到工厂类中的创建方法
产品接口
具体产品类
工厂类
Demo类

直接反射返回多态的子类实例

public class ShapeFactory{
    public static Object getShape(Class<? extends Shape> clazz){
       try{
            return (IShape) clazz.getConstructor().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
}

反射缺点

  1. 反射也就拓展方便点
  2. 程序员想用反射必须用类名.class
  3. 严重违背迪米特法则
  4. 我都知道类名了.直接 Shape shape = new Circle();不好点?
  5. 最好是情况是不管真实类名是Circle还是CirShape,我只要输入"circle"都能正确输出对应的类的实例.
  6. 这才是我们要的.枚举类满足这一切.
    在上述基础上,修改接口Shape
public interface Shape{
    static String SHAPR_SQUARE = Square.class;/Square类的全限定名
    static String SHAPR_REACTANGLE = Rectangle.class;/Rectangle类的全限定名
    static String SHAPR_Circle = Circle.class;/Circle类的全限定名
    
    void draw();
}

应用时

public class FactoryPatternDemo{
    
    Shape shape_1 = Factory.getShape(Shape.SHAPE_CIRCLE);
    shape_1.draw();
}

猜你喜欢

转载自blog.csdn.net/weixin_41474319/article/details/82974103