一个班级"使用" Java中的另一个类?实施"使用-a"类

时间:2016-06-10 20:22:46

标签: java class

我们如何"使用"一个类(Class-1)在另一个类(Class-2)中,因为Class-1只包含属性和相应的get函数和set函数,而Class-2具有所有的操作函数(以前属于Class-1) )并使用Class-1属性?

最终目标是在一个单独的文件中创建一个独立的Class-1 ---只包含属性,setter和getter以及一个包含所有方法的Class-2 ---一级。假设Class 2导入类1,并且只在主[或调用]函数中创建了Class-2对象。

一种方法是在Class-2中声明Class-1的对象,然后使用该对象的属性和get-set函数,但正如我在https://www.artima.com/objectsandjava/webuscript/ClassesObjects1.html中读到的那样,该方法是" has-a"上课,不是"使用-a"类。

那么如何实施"使用-a"类? 有关更清晰的信息,请参阅https://www.artima.com/objectsandjava/webuscript/ClassesObjects1.html

2 个答案:

答案 0 :(得分:0)

也许这是思考它的一种方式。 Square是Rectangle的子元素,Rectangle是Shape的子元素。在这种情况下,以下内容将为您提供有关架构的概念。请注意,虽然我已经将Shape称为抽象类,但由于它没有实现任何函数,因此最好将其用作接口。

更重要的是,以这种方式思考。我们正在考虑做方形/矩形。如果形状是圆形怎么办?我们真的可以依赖于Shape中的area()函数的实现吗?

[请注意,这不是编译的,我有一段时间没有编写Java。所以,请原谅语法错误。我希望得到我的观点。]

所以也许,这是我们的Shape看起来像(?)

public abstract class interface Shape

public interface Shape {
    public abstract double area();
    public abstract double perimeter();
}

Circle可以做这样的事情......

/* You might need to import the Math.. thing here 
   Note: Circle implements Shape, not extends, 
   since Shape is an interface. */
public class Circle implements Shape {
    private final double rad;
    private final double PI = Math.PI;

    public Circle(double rad) {
        this.rad = rad;
    }

    public double area() {
        return PI * Math.pow(rad, 2);
    }

    public double perimeter() {
        return 2 * PI * rad;
    }
}

现在,让我们得到Rectangle

public class Rectangle implements Shape {
    private final double WIDTH, HEIGHT; 

    public Rectangle(double width, double height) {
        this.WIDTH = width;
        this.HEIGHT = height;
    }

    public double area() {
        return this.WIDTH * this.HEIGHT;
    }

    public double perimeter() {
        return 2 * (this.WIDTH + this.HEIGHT);
    }
}

如果您考虑一下,SquareRectangle的专门案例。 (可能)在Rectangle中使用一些Square属性是有意义的。

public class Square extends Rectangle {

    // already have width, height in Rectangle 

    public Square(double side) {
        super(side, side);
    }

    // note that you do not need area 
    // and perimeter any more since Rectangle
    // has them implemented
    /* You could of course do something like this..
       public double area() {
           return super.area();
       }
    */
}

现在,结束。 "has-a" vs "use-a"。如果Square没有使用Rectangle内容,那么它现在不需要延伸,是吗?也许实施Shape就足够了。说,Square已在其中定义了字段side。那么,在这种情况下,是否值得拥有Rectangle?我想这会给你一个想法。其余部分完全取决于您的实施。如果你有很多这样的事情发生,也许可以考虑重新设计。我认为这种罕见的事情可以原谅。你将是最好的法官。

答案 1 :(得分:0)

  

我们如何"使用"一个类(Class-1)在另一个类(Class-2)中,因为Class-1只包含属性和相应的get函数和set函数,而Class-2具有所有的操作函数(以前属于Class-1) )并使用Class-1属性?

如果Class-2没有拥有任何Class-1,那么它在任何给定点上使用的唯一方法是它是否创建一个,或者如果它有一个提供给它。然而,它获得一个实例,它可以查询和操作该实例的状态,并且它可以将该实例传递给其他对象。没有其他用途是可能的,因为这是任何人都可以使用Class-1实例的全部范围。

当你说"在主[或调用]函数"中只创建了Class-2对象时,我认为你是指任何调用Class-2方法的人都没有任何类 - 提供1个实例。特别是,我假设您没有在直接创建Class-1实例的用户和间接创建一个实例的用户之间绘制一条虚线,例如通过Class-2。这种区别毫无意义。如果Class-2代表其用户创建了Class-1的实例并将其提供给用户,则用户已经有效地创建了它们。如果用户可以通过任何方式获取Class-1实例 ,那么这些方法的细节在问题的抽象层次上是无关紧要的。

只留下Class-2"使用"它根据需要自己创建的第1类实例,它仅通过局部变量和/或方法参数引用(因为它不会"具有"任何Class-1),并且它不允许是暴露给它的用户。这当然是可能的,但它的实用性有限。如果该设计有效,则可以完全删除Class-1,替换为Class-2的局部变量和方法参数。然而,考虑到原始的单级设计确实具有状态,这样的设计似乎不太可能起作用。不过,这是可能的。

另请注意,如果Class-2不拥有特定的Class-1实例,那么它唯一可以限制为仅使用的特定Class-1 instance是指如果使用仅限于在Class-2实例生命周期中只能发生一次的某些事件,例如其初始化。否则,它不是"使用 a "关系,而是使用关系。

由于原始设计同时具有状态和行为,因此似乎不可能简单地省略状态部分。在这种情况下,Class-2用户不创建任何Class-1实例的约束似乎是错误的。你也许可以通过创建另一个保持与Class-1相同状态的类来解决它,但那是荒谬的。为什么要创建一个新课程,因为已经有一个非常好的课程?如果您只是想避免Class-1直接由Class-2之外的类实例化,那么允许Class-2为其用户提供Class-1的实例。由于用户可以获取实例,因此可以将它们作为方法参数反馈给Class-2。这允许Class-2使用Class-1而不拥有自己的Class-1。例如,

public class State {
    private int x;

    State(int x) {  // package-private
        this.x = x;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }
}

public class Behavior {
    // Uses State, but is not a State and does not have a State

    public State doSomethingThatYieldsState(String s) {
        try {
            return new State(Integer.parseInt(s));
        } catch (NumberFormatException nfe) {
            return null;
        }
    }

    public int doSomethingWithState(State s, int y) {
        return y + s.getX();
    }

    public void doSomethingToState(State s) {
        s.setX(s.getX() + 1);
    }
}