【问题标题】:Why don't use static variable to share object for the subclass?为什么不使用静态变量为子类共享对象?
【发布时间】:2012-10-31 06:56:54
【问题描述】:

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

我有一个抽象工厂的抽象类。 我想分享混凝土工厂所需的“资源”。 所以我只是将 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 variable instance 而不是 static variable ,当我实例化具体工厂时,我从外部传递向量。

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

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 当我创建一个具体工厂的实例时。

【问题讨论】:

  • 你的向量的目的是什么?我还必须说,任何甚至提到 Vector 的课程都是高度可疑的。这个类已经过时了十多年了。
  • Vector 可能是缓存吗?在不同的工厂实现之间共享对象没有多大意义。特别是因为抽象工厂在实践中的意义在于让库的客户能够提供自己的工厂实现。
  • 在原始版本的代码中,具体工厂创建的产品都需要在其构造函数中使用Vector,这意味着产品需要相同的向量,并且工厂应该具有相同的向量,这样他们可以使产品具有相同的向量。有没有更好的设计来解决这个问题?
  • 每一个设计选择都以全图分析为准。如果不知道向量的确切作用,就不可能说什么是更好的设计。如果向量实际上是一个全局变量,那么将它放在静态变量中是有意义的。但是,我看不到一个现实的场景,即必须从所有这些产品对象中访问全局变量。通常它会隐藏在一个提供内部需要该变量的服务的 API 后面。
  • 使用实例方法返回静态变量的值是您的提议的一个明确问题。如果类需要访问该共享资源,那么要么使用public static final Vector,要么使用private static final Vectorpublic static Vector getVector()。如果子类可以覆盖它并提供不同的向量,那么您的方式仍然有意义,但这种设计必须有原因。

标签: java oop design-patterns


【解决方案1】:

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

一些例子:你并不总是知道你的类将被使用的环境。也许你的工厂的不同实例最终会被不同的类加载器加载(这在 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 对这类事情来说是个好主意 - 它可以防止您意外更改代码中其他地方的变量。但这是可选的。我所做的关键更改是将向量添加到抽象基类的构造函数中,然后从超类传入。

【讨论】:

  • 我想我明白你的意思。使用静态变量来共享对象就像为屏幕后面的多个工厂实例共享向量一样。由于vector的分享是在屏后完成的,以后别人或者我自己查看代码的时候,很难知道那些工厂用的是同一个vector。它可能会导致不可预测的行为,因为我们不知道它们使用的是相同的向量。比如实例AcreateCircle(),它影响了实例B,我们通过查看程序代码很难找出他们影响别人的原因。
  • 是的 - 你明白了。如果意图是真正在整个应用程序的每个地方都使用一个 Vector 实例,那么您正在寻找一个单例,并且有比使用静态变量更好的实现单例的方法(每个有效 Java 枚举是一个很好的这样做的方式)。但是最好避免使用 Singleton,除非您真的知道自己在做什么(有时它是合适的 - 但大多数明显的情况最好以其他方式处理)。随着您继续学习,请记住:“封装”。
  • PS - 你的问题问得很好。大多数学生在提出让我想回答的问题时遇到问题——你对学习过程的态度(寻求理解,而不仅仅是寻求答案)令人耳目一新——并且会让你走得更远。继续加油!
  • 感谢您的鼓励 :) 事实上,我一直怀疑我的学习方法是缓慢而低效的。我一直很欣赏我的一些同学,他们只需通过一些示例和在线教程学习就可以轻松掌握技术技能。与其通过网上的例子和教程来学习,我更喜欢看书,因为我可以对这个主题有更全面的理解。但是,我始终怀疑阅读一本书是否真的更好。对了,我还会记得“封装”。顺便说一句,你是老师吗:)?
【解决方案2】:

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 不是Factory 实例的属性,而是Factory 本身的属性!

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

相信你的老师 - 他是对的;)

【讨论】:

  • 所以static不是用来共享资源的,它是用来表示在运行时只有一次的东西,比如常量和方法总是给出相同的输出?另外,你所说的糟糕、丑陋的编码风格是什么意思?您的意思是该方法应该是静态的才能访问静态变量吗?
【解决方案3】:

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

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

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

【讨论】:

  • +1 工厂可以基于上下文并且彼此独立,将传入向量。 +1 单元测试可以更彻底,因为我可以轻松控制一切的状态,无论是工厂还是向量。我希望我可以“勾选”所有答案作为最佳答案。但是我已经勾选了另一个,非常感谢您的解释:)
猜你喜欢
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 2017-03-22
  • 2011-12-09
相关资源
最近更新 更多