0

我的问题有点长。我正在学习抽象工厂模式

我有一个抽象工厂的抽象类。我想分享混凝土工厂所需的“资源”。所以我只是将 AbstractFactory 中的变量设为静态

public class AbstractFactory{
    private static Vector vector = new Vector();

    protected Vector void getVector() {
        return vector;
    }

    protected void setVector(Vector v){
        this.vector = v;
    }

    public abstract Circle createCircle();
}

它的子类看起来像:

public class ConcreteFactory extends AbstractFactory{
    public ConcreteFactory(){
        super();
    }

    public Circle createCircle(){
        Circle circle = new Circle();
        getVector().add(circle);
        return circle;
    }
}

但是,我的老师说我不应该使用静态对象实例,因为静态变量经常用于一些常量。

因此,我对Vector使用实例变量 instance而不是静态变量 ,并且在实例化具体工厂时从外部传递向量。

所以我的课程的新设计将如下所示:

public class AbstractFactory{
    private Vector vector;

    protected Vector void getVector() {
        return vector;
    }

    protected void setVector(Vector v){
        this.vector = v;
    }

    public abstract Circle createCircle();
}

public class ConcreteFactory extends AbstractFactory{
    public ConcreteFactory(Vector v){
        super();
        setVector(v);
    }

    public Circle createCircle(){
        Circle circle = new Circle();
        getVector().add(circle);
        return circle;
    }
}

**

我的问题是:为什么我不应该使用静态变量来共享对象?

**

当我创建具体工厂的实例时,在不传入 Vector 的情况下,在具体工厂之间共享资源会更容易。

4

3 回答 3

2

有时,今天让你的生活更轻松的东西会让你的生活变得更加困难。

一些例子: 你并不总是知道你的类将被使用的环境。也许你的工厂的不同实例最终会被不同的类加载器加载(这在 Web 应用程序中经常发生)。以这种方式使用静态实例变量可能会导致完全不可预测的行为。静态变量几乎总是一个坏主意。

也就是说,我认为你在课堂上真正想做的是:

public class AbstractFactory{
    private final Vector vector;

    protected AbstractFactory(Vector vector){
        this.vector = vector;
    }

    protected Vector void getVector() {
        return vector;
    }

    public abstract Circle createCircle();
}

public class ConcreteFactory extends AbstractFactory{
    // USE THIS IF YOU NEED TO SHARE THE VECTOR AMONGST MULTIPLE FACTORY INSTANCES
    public ConcreteFactory(Vector vector){
        super(vector);
    }
    // OR USE THIS IF THE VECTOR IS SPECIFIC TO THE FACTORY
    public ConcreteFactory(){
        super(new Vector());
    }    

    public Circle createCircle(){
        Circle circle = new Circle();
        getVector().add(circle);
        return circle;
    }
}

在实例变量上使用 final 对于这类事情是一个好主意 - 它可以防止您意外更改代码中其他地方的变量。但这是可选的。我所做的关键更改是将向量添加到抽象基类的构造函数中,然后从超类传入。

于 2012-11-11T18:05:24.180 回答
1

static属性并不意味着以这种方式使用。
statics 是一些东西,在运行时只能使用一次。
在您的情况下,这意味着您的所有工厂AbstractFactory都将共享这个单一的向量。

看这个例子:

ConcreteFactory a = new ConcreteFactory();
ConcreteFactory b = new ConcreteFactory();
a.createCircle();
b.createCircle();

两个对象ab现在将在向量中有两个条目,因为它们共享相同的静态向量。

我也认为,

protected void setVector(Vector v){
    this.vector = v;
}

是非法的,因为vector不是工厂实例的属性,而是工厂本身的属性!

除此之外,它只是一种糟糕的、容易出错的(尝试在更大范围内调试)和简单丑陋的编码风格。

只要相信那里的老师-他是对的;)

于 2012-11-11T18:04:34.543 回答
1

静态最终变量有时用作常量这一事实不应阻止您使用相同的机制,只要它服务最好(记录器是我能给出的唯一其他示例)。

不过,当没有与外部世界的隐式组件耦合时,这总是好的。如果将向量定义为静态变量,则用户无法使您的工厂基于上下文且彼此独立。如果你将向量作为工厂的参数,那么由工厂创建者(现在通常是 Spring 上下文加载器)来定义哪些工厂共享向量,哪些不共享。

在您的案例中将向量作为参数传递的另一个原因与单元测试方面有关。如果您的课程旨在从外部获取矢量,您可以模拟它并更彻底地测试您的课程。

于 2012-11-11T18:17:24.390 回答