多态性实现强制对子类字段的常见修改

huangapple go评论91阅读模式
英文:

Polymorphism implement forced common alterations to child's fields

问题

什么是强制抽象类的子类调用在抽象类中定义的、修改其实现的抽象变量值的最佳设计模式?

问题:

我希望根据屏幕大小按比例缩放位图。我希避免拥有多个本质上以相同方式赋值的抽象变量。例如,在这种情况下,widthScale * width 将在赋值给宽度时缩放宽度。如果我创建一个名为 scaleWidth() 的抽象方法,尽管它会向类的用户暗示他们应该实现这样的功能,但会导致在整个代码库中重复实现相同的方法。

另外,在抽象类中无法有一个缩放后的宽度变量,它会乘以2个抽象变量,因为父类的字段会在子类之前初始化;

伪代码示例:

抽象类 Image
{
  抽象的整数 width;
}

类 Apple 扩展 Image
{
  覆盖 整数 width = 100 * StaticAppClass.scaleFactorWidth;
}

类 Banana 扩展 Image
{
  覆盖 整数 width = 50 * StaticAppClass.scaleFactorWidth;
}

因此,正如您所见,每次程序员都需要将宽度乘以 StaticAppClass.scaleFactorWidth。这不仅不方便,而且也不够明确。这意味着程序员甚至都不会知道他必须这样做。

英文:

What's the best design pattern to force children of an abstract class to call a function defined in the abstract class that alters the value of its implemented abstract variables?

<br>

The problem:

I want to scale my bitmaps according to the screen size to keep the ratio. I want to avoid having multiple abstract variables that are essentially assigned the same way. For example in this case widthScale * width will scale the width when assigned to the width. If I create an abstract method named scaleWidth(), though it would imply to the user of the class that they should implement such functionality, it'd cause a repetitious implementation of the same method throughout the codebase.

Also can't have a scaledWidth variable in the abstract class that multiplies 2 abstract variables since parent's fields are initialized before the childrens'

Pseudocode example:

Abstract Class Image
{
  abstract int width;

}

Class Apple extends Image
{
  override int width = 100 * StaticAppClass.scaleFactorWidth;

}

Class Banana extends Image
{
  override int width = 50 * StaticAppClass.scaleFactorWidth;
}

So as you can see every time the programmer has to multiply the width with the StaticAppClass.scaleFactorWidth. Not only it's inconvenient also it's not explicit. Meaning, the programmer wouldn't even know he has to do that

答案1

得分: 2

绑定到成员字段是在编译时发生的,因此没有直接实现您想要的方式。也就是说,字段没有像 @Override 一样的机制。我认为最好的方法如下所示:

public static final int scaleFactor = 10;

public abstract class A {
    public int getScaledWidth() {
        return this.getWidth() * scaleFactor;
    }
    public abstract int getWidth();
}

public class B extends A {
    public int width = 50;
    @Override
    public int getWidth() { return width; }
}

public class C extends A {
    public int width = 100;
    @Override
    public int getWidth() { return width; }
}

public static void main(String[] args) {
    B b = new B();
    System.out.println(b.getScaledWidth());
    C c = new C();
    System.out.println(c.getScaledWidth());
}

通过这种结构,在编写 A 的新特化时,开发人员将被要求提供 getWidth() 方法,从而强制他们考虑所需的内容。

英文:

Binding to member fields happens at compile time, so there's no way to directly do what you want. I.e. there's no @Override for fields. I believe the best way is as follows:

public static final int scaleFactor = 10;

public abstract class A
{
    public int getScaledWidth()
    {
        return this.getWidth() * scaleFactor;
    }
    public abstract int getWidth();
}

public class B extends A
{
    public int width = 50;
    @Override
    public int getWidth() { return width; }
}

public class C extends A
{
    public int width = 100;
    @Override
    public int getWidth() { return width; }
}

public static void main(String[] args)
{
    B b = new B();
    System.out.println(b.getScaledWidth());
    C c = new C();
    System.out.println(c.getScaledWidth());
}

With this structure, when writing a new specialization of A, the developer will be required to provide getWidth(), forcing them to consider what is needed.

答案2

得分: 1

你难道不能让子类分配它们的宽度值,然后让超类实现一个``scaledWidth``获取器吗?(你说过你用的是 Kotlin,我也用 Kotlin 模式来举个例子!)

    abstract class Image {
        abstract val width: Int
        val scaleFactorWidth = 2
        fun getScaledWidth() = width * scaleFactorWidth
    }

    class Banana : Image() {
        override val width = 100
    }

这样,子类需要实现的唯一内容就是``width``属性(我是指最好将其传递到构造函数中,但属性可能太多了)。缩放宽度是通过getter函数访问的,因此在任何人调用它之前,所有内容都已初始化。

如果你使用的是 Kotlin,甚至可以这样写:

    val scaledWidth by lazy { width * scaledWidth }

它只存储一个值,但会在首次访问时计算它(仅计算一次)- 只要不是在``Image``超类的初始化期间访问它,就应该没问题。
英文:

Couldn't you just have the subclasses assign their width values, and have the superclass implement a scaledWidth getter? (You said Kotlin and I'm in Kotlin mode so here's my example!)

abstract class Image {
    abstract val width: Int
    val scaleFactorWidth = 2
    fun getScaledWidth() = width * scaleFactorWidth
}

class Banana : Image() {
    override val width = 100
}

that way the only thing the subclasses need to implement is a width property (I mean it would be better to pass them into the constructor but there might be too many properties for that). The scaled width is accessed through a getter function, so it's all initialised by the time anyone calls it.

If you are in Kotlin you could even do

val scaledWidth by lazy { width * scaledWidth }

which stores a single value, but calculates it (once) when it's first accessed - so long as that's not during the initialisation of the Image superclass, you should be ok?

答案3

得分: -1

如果我理解正确,width 是一个对于每个实现都不同的常量?

我会这样做:

在抽象类中:

public abstract int getWidth();

在实现类中:

@Override
public int getWidth() {
    return value;
}
英文:

If I understand well, width is a constant different for each implementation?

I would do something like that:

In the abstract class:

public abstract int getWidth();

In the implementations:

@Override
public int getWidth() {
    return value;
}

huangapple
  • 本文由 发表于 2020年10月23日 00:46:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/64486824.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定