版权声明:之江学院 黄日超 https://blog.csdn.net/weixin_41474319/article/details/82974103
先修知识
多态
- 接口与父类可作返回类型,引用声明类型.
- 实现类与继承类可作构造类型,反射强制转换类型,反射(子类.class)获取元类型
利用反射拓展工厂生产能力
反射一定是用在通用的场景,故利用反射机制时不应该出现具体类的名字,最多用到接口或抽象类.
- 定义输入参数:public static Object getClass(Class<?extends Shape> clazz)//定义元类型Class的范围,必须满足是Shape的子类
ps:如何输入(Class clazz)元类型?
通过类的元类型 Class clazz=Object.class 或对象的元类型 Class clazz.=obj.getClass().
- 获取元类型对象对应的类型名:clazz.getName()
- 根据类名加载对应的类,运行其中的静态方法:Class.forName(clazz.getName())
- 加载完后创建对应的实例:Object obj = Class.forNmae(clazz.getName()).getInstance();
- return obj;
应用反射工厂类时人们一般都写好了具体类,人们是知道具体类名的
- 利用反射机制获取对应类的类对象:Object obj = ShapeFactory.getClass(Square.class)
- 用具体类强制转换:Square square = (Square) ShapeFactory.getClass(Square.class);
- 完美实现子类的拓展,且不用修改工厂类的源码
工厂模式
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();
}
}
工厂模式总结
直接反射返回多态的子类实例
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;
}
}
反射缺点
- 反射也就拓展方便点
- 程序员想用反射必须用类名.class
- 严重违背迪米特法则
- 我都知道类名了.直接 Shape shape = new Circle();不好点?
- 最好是情况是不管真实类名是Circle还是CirShape,我只要输入"circle"都能正确输出对应的类的实例.
- 这才是我们要的.枚举类满足这一切.
在上述基础上,修改接口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();
}