工厂设计模式你会了没,没有还不看看!!!

使用反射机制可以解决每次增加一个产品时,都需要增加一个对象实现工厂的缺点

public class ShapeFactory {
public static Object getClass(Class clazz) {
Object obj = null;

    try {
        obj = Class.forName(clazz.getName()).newInstance();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

    return obj;
}

}
使用的使用采用强制转换

Rectangle rect = (Rectangle) ShapeFactory.getClass(Rectangle.class);
rect.draw();
Square square = (Square) ShapeFactory.getClass(Square.class);
square.draw();
这样就只需要一个对象实现工厂

21
public class ShapeFactory {
public static T getClass(Class clazz) {
T obj = null;

    try {
        obj = (T) Class.forName(clazz.getName()).newInstance();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

    return obj;
}

}
省略类型强制转换,支持多态

Rectangle rect = ShapeFactory.getClass(Rectangle.class);
rect.draw();

Shape square = ShapeFactory.getClass(Square.class);
square.draw();
8
在上面的基础上进一步扩展,针对多个接口实现一个公共的工厂类:

public class ObjectFactory {
public Object getObject(Class clazz) {
if (clazz == null ) {
return null;
}
Object obj = null;
try {
obj = Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}
8
在jdk9中直接使用泛型的newInstance方法已经过时。重写的getClass()方法如下:

public T getClass(Class clazz) {
T obj = null;
try {
obj = clazz.getDeclaredConstructor().newInstance();
}
catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return obj;
}

11
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;
}
}
创建的这个工厂,这个创建函数,没能看出有什么特别的,还特别繁琐,如果IShape类太多,那么if else语句也将增加太多,不好维护,与其这样写,还不如改成如下:

public class ShapeFactory {

//使用 getShape 方法获取形状类型的对象
public Shape getShape(Class 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;
}
}
这样写在创建时也不用知道具体的类别,易于管理维护。

其实使用反射是一种不错的办法,但反射也是从类名反射而不能从类反射!

先看一下工厂模式是用来干什么的——属于创建模式,解决子类创建问题的。换句话来说,调用者并不知道运行时真正的类名,只知道从“Circle"可以创建出一个shape接口的类,至于类的名称是否叫’Circle",调用者并不知情。所以真正的对工厂进行扩展的方式(防止程序员调用出错)可以考虑使用一个枚举类(防止传入参数时,把circle拼写错误)。

如果调用者参肯定类型是Circle的话,那么其工厂没有存在的意义了!

比如 IShape shape = new Circle();这样不是更好?也就是说调用者有了Circle这个知识是可以直接调用的,根据DP(迪米特法则)其实调用者并不知道有一个Circle类的存在,他只需要知道这个IShape接口可以计算圆面积,而不需要知道;圆这个类到底是什么类名——他只知道给定一个”circle"字符串的参数,IShape接口可以自动计算圆的面积就可以了!

其实在.net类库中存在这个模式的的一个典型的。但他引入的另一个概念“可插入编程协议”。

那个就是WebRequest req = WebRequest.Create(“http://ccc…”);可以自动创建一个HttpWebRequest的对象,当然,如果你给定的是一个ftp地址,他会自动创建一个FtpWebRequest对象。工厂模式中着重介绍的是这种通过某个特定的参数,让你一个接口去干对应不同的事而已!而不是调用者知道了类!

比如如果圆的那个类名叫"CircleShape“呢?不管是反射还是泛型都干扰了你们具体类的生成!其实这个要说明的问题就是这个,调用者(clinet)只知道IShape的存在,在创建时给IShape一个参数"Circle",它可以计算圆的面积之类的工作,但是为什么会执行这些工作,根据迪米特法则,client是不用知道的。

我想问一下那些写笔记的哥们,如果你们知道了泛型,那么为什么不直接使用呢?干吗还需要经过工厂这个类呢?不觉得多余了吗?

如果,我只是说如果,如果所有从IShape继承的类都是Internal类型的呢?而client肯定不会与IShape一个空间!这时,你会了现你根本无法拿到这个类名!

Create时使用注册机制是一种简单的办法,比如使用一个枚举类,把功能总结到一处。而反射也是一种最简单的办法,调用者输入的名称恰是类名称或某种规则时使用,比如调用者输入的是Circle,而类恰是CircleShape,那么可以通过输入+”Shape"字符串形成新的类名,然后从字符串将运行类反射出来!

工厂的创建行为,就这些作用,还被你们用反射或泛型转嫁给了调用者(clinet),那么,这种情况下,要工厂类何用?!

13
使用枚举优化

public enum Factory {
CIRCLE(new Circle(),“CIRCLE”),
RECTANGLE(new Rectangle(),“RECTANGLE”),
SQUARE(new Square(),“SQUARE”);

// 成员变量  
private Shape shape;  
private String name;  

// 普通方法  
public static Shape getShape(String name) {  
    for (Factory c : Factory.values()) {  
        if (c.name == name) {  
            return c.shape;  
        }  
    }  
    return null;  
} 
// 构造方法  
private Factory(Shape shape, String name) {  
    this.shape = shape;  
    this.name = name;  
} 
public String getName() {
    return name;
}
public Shape getShape() {
    return shape;
}


public void setShape(Shape shape) {
    this.shape = shape;
}


public void setName(String name) {
    this.name = name;
} 

}

/使用枚举类/
Factory.getShape(“CIRCLE”).draw();
Factory.getShape(“RECTANGLE”).draw();
Factory.getShape(“SQUARE”).draw();

11
使用类名增加耦合性,那就需要使用常量或者枚举类解耦合。

// 接口 增加常量或枚举
public interface Shape {
static String SHAPE_YUAN = Yuan.class.getName();
static String SHAPE_FANG = Fang.class.getName();
static String SHAPE_CHANG = Chang.class.getName();
void draw();
}

// 工厂方法
public class Factory {
public static Shape getShape2(String type) {
try {
return (Shape) Class.forName(type).getDeclaredConstructor().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();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}

// 调用

Shape s21 = Factory.getShape2(Shape.SHAPE_CHANG);
s21.draw();

Shape s22 = Factory.getShape2(Shape.SHAPE_FANG);
s22.draw();

Shape s23 = Factory.getShape2(Shape.SHAPE_YUAN);
s23.draw();

9

增加枚举类

public enum ShapeType{
CIRCLE,
RECTANGLE,
SQUARE
}
修改工厂类的工厂方法,个人建议工厂方法应该是静态方法或者采用单例模式:

public class ShapeFactory{
public static Shape getShape(ShapeType type){
switch(type){
case CIRCLE:
return new Circle();
case RECTANGLE:
return new Rectangle();
case SQUARE:
return new Square();
default:
throw new UnknownTypeException();
}
}
}
上面用到的类和接口与课程中的一样。

最后是使用示例:

public class FactoryPatternDemo {
public static void main(String[] args) {
//获取 Circle 的对象,并调用它的 draw 方法
Shape shape1 = ShapeFactory.getShape(ShapeType.CIRCLE);

    //调用 Circle 的 draw 方法
    shape1.draw();

    //获取 Rectangle 的对象,并调用它的 draw 方法
    Shape shape2 = ShapeFactory.getShape(ShapeType.RECTANGLE);

    //调用 Rectangle 的 draw 方法
    shape2.draw();

    //获取 Square 的对象,并调用它的 draw 方法
    Shape shape3 = ShapeFactory.getShape(ShapeType.SQUARE);

    //调用 Square 的 draw 方法
    shape3.draw();
}

}

26
一、一句话概括工厂模式

简单工厂:一个工厂类,一个产品抽象类。
工厂方法:多个工厂类,一个产品抽象类。
抽象工厂:多个工厂类,多个产品抽象类。
二、生活中的工厂模式

简单工厂类:一个麦当劳店,可以生产多种汉堡。
工厂方法类:一个麦当劳店,可以生产多种汉堡。一个肯德基店,也可以生产多种汉堡。
抽象工厂类:百胜餐饮集团下有肯德基和百事公司,肯德基生产汉堡,百事公司生成百事可乐。

8
工厂模式实例:

package 工厂设计模式;

public class Factory_pattern {
public static void main(String[] args) {
Factory facortoy = new Factory();
Person zgr = facortoy.getInstance(“zgr”);
zgr.eat();
}
}

//人类都具有吃方法
interface Person{
public void eat();
}

//中国人
class zgr implements Person{

@Override
    public void eat() {
    System.out.println("中国人吃饭用筷子");
}

}

//印度人
class ydr implements Person{

@Override
public void eat() {
    System.out.println("印度人用手吃饭");
}

}

//美国人
class mgr implements Person{

@Override
public void eat() {
    System.out.println("美国人用刀和叉子吃饭");
}

}

interface Instance{
public Person getInstance(String str);
}

class Factory implements Instance{
@Override
public Person getInstance(String str) {
if(str.equals(“zgr”)) {
return new zgr();
}else if(str.equals(“ydr”)) {
return new ydr();
}else if(str.equals(“mgr”)) {
return new mgr();
}else {
return null;
}
}
}

根据上面 @枚举的思路实现的工厂模式:

public enum ShapeType {
CIRCLE(new Circle()), RECTANGLE(new Rectangle()), SQUARE(new Square());
private Shape shape;
private ShapeType(Shape shape) {
this.shape = shape;
}

public Shape getShape() {
    return shape;
}

}

public class Test {
public static void main(String[] args) {
ShapeType.CIRCLE.getShape().draw();
}
}

4
接口定义实现类的规范,通过反射工厂类进行生产,完整的一个过程就是。

接口类:

public interface Shape {
void draw();
}
实现类:

public class Rectangle implements Shape{
@Override public void draw() {
System.out.println(“Rectangle”);
}
}

public class Square implements Shape{
@Override public void draw() {
System.out.println(“Square”);
}
}
工厂类:

public class ShapeFactory{
public static Shape getClass(Class clazz) {
Shape o = null;
try {
o = (Shape) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return o;
}
}
}
给定条件产出:

public class FactoryModeImpl {
public static void main(String[] args) {
Shape shape = ShapeFactory.getClass(Square.class);
shape.draw();
}
}

3
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

此练习中我写的工厂是通过一个方法(买狗)来调用相应对象创建语句去创建不同的(狗)对象;用子对象中的重写方法验证父对象被赋值后调用的方法是属于谁的。

具体的解释在代码中已经标明:

import java.util.Scanner;
//多态
public class Test2 {
public static void main(String[] args) {
Factory no1=new Factory();//创建工厂对象
no1.maigou();//调用工厂的方法(买狗)
}
}
class Factory{
public void maigou(){
Dog1 dog=new Dog1();
System.out.println(“要买什么狗?”);
Scanner sc=new Scanner(System.in);
String str=sc.nextLine();
switch(str){
default:
System.out.println(“没有这玩意儿”);
break;
case “金毛” :
dog=new Jinmao();
dog.show();
break;//将子类赋值给父类并调用重写后的方法
case “二哈” :
dog=new Erha();
dog.show();//将子类赋值给父类并调用重写后的方法
}
}
}
class Dog1{ //这里因为Dog类在其他包里建过了,为了避免冲突,取名Dog1
public void show(){
System.out.println(“这是一只狗”);
}
}
class Erha extends Dog1{
public void show(){
System.out.println(“这是一只二哈”);//通过重写函数show验证dog对象调用的方法是谁的
}
}
class Jinmao extends Dog1{
public void show(){
System.out.println(“这是一只金毛”);//通过重写函数show验证dog对象调用的方法是谁的
}
}

2
python 代码实现示例:

class Shape(object):
def draw(self):
pass

class RectangleImplementsShape(Shape):
def init(self):
print(“this relalize Interface”)
def draw(self):
print(“Inside Rectangle::draw() method.”)

class SquareImplementsShape(Shape):
def init(self):
print(“this relalize Interface”)
def draw(self):
print(“Inside Square::draw() method.”)

class CircleImplementsShape(Shape):
def init(self):
print(“this relalize Interface”)
def draw(self):
print(“Inside Circle::draw() method.”)

class ShapeFactory(object):
def init(self):
print(“ShapeFactory init”)
def getShape(self,method):
if method.lower() == ‘rectangle’:
return RectangleImplementsShape()
if method.lower() == ‘square’:
return SquareImplementsShape()
if method.lower() == ‘circle’:
return CircleImplementsShape()

shapeFactory = ShapeFactory()

shap1 = shapeFactory.getShape(‘Rectangle’)
shap2 = shapeFactory.getShape(‘Square’)
shap3 = shapeFactory.getShape(‘Circle’)

shap1.draw()
shap2.draw()
shap3.draw()

Python 方式:

Python原生默认不支持接口,默认多继承,所有的方法都必须不能实现

from abc import abstractmethod,ABCMeta

声明一个抽象接口

class Shape(metaclass=ABCMeta):
@abstractmethod
def draw(self):
pass

三个形状继承实现 Shape 接口

class Rectangle(Shape):
def draw(self):
print(“Inside Ractangle.draw method”)

class Square(Shape):
def draw(self):
print(“Inside Square.draw method”)

class Circle(Shape):
def draw(self):
print(“Inside Circle.draw method”)

创建一个工厂

class ShapeFactory():
def getShape(self,shapeType):
if shapeType == None :
return None
elif shapeType.upper() == “CIRCLE”:
return Circle()
elif shapeType.upper() == “RECTANGLE”:
return Rectangle()
elif shapeType.upper() == “SQUARE”:
return Square()
return None

输出

if name == ‘main’:
shapeFactory = ShapeFactory()
shape1 = shapeFactory.getShape(“CIRCLE”)
shape1.draw()
shape2 = shapeFactory.getShape(“RECTANGLE”)
shape2.draw()
shape3 = shapeFactory.getShape(“SQUARE”)
shape3.draw()

你可能感兴趣的:(工厂设计模式你会了没,没有还不看看!!!)