简体   繁体   English

抽象工厂模式-实现它的正确方法

[英]Abstract Factory Pattern - Right way to implement it

Here's my code 这是我的代码

public class FactoryPatternDemo {
public static void main(String[]args)
{
    AbstractFactory shapeFactory=new ShapeFactory();

    //tramite la fabbrica di figura geometrica disegno un rettangolo..
    Shape shape1=shapeFactory.getShape("rEcTaNgLe");
    shape1.draw();

    System.out.println();

    //..e un triangolo
    Shape shape2=shapeFactory.getShape("triangle");
    shape2.draw();
}

Shape Factory: 形状工厂:

public class ShapeFactory extends AbstractFactory{

public ShapeFactory(){

}

@Override
public Shape getShape(String shapeType)
{
    if (shapeType==null)
            return null;
    if (shapeType.equalsIgnoreCase("RECTANGLE"))
            return new Rectangle();
    if (shapeType.equalsIgnoreCase("TRIANGLE"))
            return new Triangle();
    return null;
}

Abstract Factory: 抽象工厂:

public abstract class AbstractFactory {
public abstract Shape getShape(String shapeType);}

Abstract Product 抽象产品

public interface Shape {
void draw();}

Concrete Product#1 混凝土产品#1

public class Rectangle implements Shape {

@Override
public void draw() {
    for(int i=0; i<5; i++)
    {
        if(i==0 || i==4)
        {
            for(int j=0; j<10; j++)
            {
                System.out.print("*");
            }
        }
        else
        {
            for(int j=0; j<10; j++)
            {
                if(j==0||j==9)
                    System.out.print("*");
                else
                    System.out.print(" ");
            }
        }
        System.out.print("\n");
    }

}

My question is: is this the right way to implement an Abstract Factory pattern? 我的问题是:这是实现抽象工厂模式的正确方法吗? The client should be only able to see abstract things or interfaces in the FactoryPatternDemo class, but this line of code: 客户端应该只能看到FactoryPatternDemo类中的抽象事物或接口,但是以下代码行:

 AbstractFactory shapeFactory=new ShapeFactory();

shows the name of a concrete factory. 显示混凝土工厂的名称。 Is this an error? 这是错误吗? Thanks guys 多谢你们

Well, for sure I would not use this design! 好吧,可以肯定我不会使用这种设计! It smells because of at least the following reasons: 至少由于以下原因,它会闻起来:

  1. ShapeFactory.getShape() uses a kind of a switch, which is not Object Oriented Design. ShapeFactory.getShape()使用一种开关,它不是面向对象的设计。
  2. ShapeFactory is compile-time dependent on all your Shape objects. ShapeFactory的编译时依赖于所有Shape对象。
  3. No-one cannot extend you library! 没有人可以扩展您的库! Try to imagine, how someone who does not have control over your ShapeFactory want to add a new shape... Impossible! 试想一下,一个对您的ShapeFactory 没有控制权的ShapeFactory想如何添加新形状……不可能!
  4. I cannot see any reason why AbstractFactory should be an abstract class and not an interface. 我看不到任何为什么AbstractFactory应该是抽象类而不是接口的原因。 It seems to me like a heritage from C++ rather than a Java design. 在我看来,这似乎是C ++的遗产,而不是Java设计。

Have a look at the way how the java.sql.DriverManager.getConnection(connectionString) method is implemented. 看一下java.sql.DriverManager.getConnection(connectionString)方法的实现方式。 The best way is to watch the source code. 最好的方法是观看源代码。

Very rough summary of the idea (it is hidden inside a lot of private methods). 非常粗略的想法总结(它隐藏在许多私有方法中)。 It is more or less an implementation of chain of responsibility, although there is not linked list of drivers. 尽管没有驱动程序的链接列表,但它或多或少是责任链的一种实现。

DriverManager manages a list of drivers. DriverManager管理驱动程序列表。 Each driver must register itself to the DriverManager by calling its method registerDriver() . 每个驱动程序必须通过调用其方法registerDriver()来向DriverManager注册自己。 Upon request for a connection, the getConnection(connectionString) method sequentially calls the drivers passing them the connectionString. 在请求连接时, getConnection(connectionString)方法顺序调用向驱动程序传递getConnection(connectionString)的驱动程序。 Each driver KNOWS if the given connection string is within its competence. 如果给定的连接字符串在其权限范围内,则每个驱动程序都会知道。 If yes, it creates the connection and returns it. 如果是,它将创建连接并返回它。 Otherwise the control is passed to the next driver. 否则,控制权将传递给下一个驱动程序。 Analogy: 比喻:

  • drivers: your concrete ShapeFactories 驱动程序:您的具体ShapeFactories
  • connection strings: types of your shapes 连接字符串:形状的类型
  • connection: an instance of a shape 连接:形状的实例

I would try something like this: 我会尝试这样的事情:

public class ShapeManager {
    public void registerFactory(ShapeFactory factory) {
        // store the factory to the internal list
    }
    public shape getShape(String shapeType) {
        // go through the list of registered factories until one of them returns non-null
    }
}

public interface ShapeFactory {
    /**
     * Returns an instance of a shape, if shapeType is supported
     */
    public shape getShape(String shapeType);
}

public class TriangleFactory implements ShapeFactory {
    public static final String SHAPE_TYPE = "Triangle";
    @Override 
    public shape getShape(String shapeType) {
        if (SHAPE_TYPE.equals(shapeType) {
            return new Triangle();
        }
    }
}

public class RectangleFactory implements ShapeFactory {
    public static final String SHAPE_TYPE = "Rectangle";
    @Override 
    public shape getShape(String shapeType) {
        if (SHAPE_TYPE.equals(shapeType) {
            return new Triangle();
        }
    }
}

public class Client {
    ShapeFactory factory;

    // This is performed somehow on a global level, maybe by Spring configuration or so
    // However it is *not* part of the ShapeFactory so anyone may add their own shapes,
    // apart from those provided by default by your shape library.
    public void setUp() {
       factory = new ShapeFactory();
       factory.registerFactory(new TriangleFactory());
       factory.registerFactory(new RectangleFactory());
    }

    public void use() {
        final Shape triangle = factory.getShape("Triangle");
        final Shape rectangle = factory.getShape("Rectangle");
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM