当不同的类使用相同的方法但具有不同的构造函数时,如何避免重复的代码?

How to avoid repetitive code when different classes use the same methods but have different constructors?

提问人:Tobias Dräger 提问时间:9/14/2023 最后编辑:Tobias Dräger 更新时间:9/19/2023 访问量:57

问:

我已经在代码上工作了几个月,它工作得很好,但是我添加的功能越多,我就越想以某种方式减少代码量,因为我在各种类中使用相同的函数。

该代码由一个名为“Shape”的原始类组成,此处创建了各种函数。然后这里有各种称为“形”和“六边形”的新类。在这些的构造函数中,类“Shape”用行“”和“”调用。否则,类Rectangle”、“Hexagon”等使用相同的函数(例如“”),唯一的区别是数组的引用,例如“Rectangle”类中的“”和类“Hexagon”中的”。this.rec = new Shape {...}this.hex = new Shape {...}plotShapethis.rec.xCoordinatesthis.hex.xCoordinates

在代码的后面部分,这些类与行 “” 和 “” 一起使用。recShape = new Rectangle {...}hexShape = new Hexagon {...}

所以我的问题是,什么是减少代码重复的好方法?

首先,一些代码片段可以更好地理解我在说什么。

下面是原始类的构造函数以及该类中包含的函数:

export class Shape {
    constructor (options) {
        this.size = options.size
        this.type = options.type
        switch (this.type) {
            ...
            case 4:
                this.gridsizex = options.gridsizex
                this.gridsizey = options.gridsizey
                break
            case 6:
                this.gridsize = options.gridsize
                break
        }
        this.xCoordinates = new Float64Array()
        this.yCoordinates = new Float64Array()
    }

    createShape() {
        this.xCoordinates = new Float64Array(this.size * this.size)
        this.yCoordinates = new Float64Array(this.size * this.size)
        switch (this.type) {
            ...
            case 4:
                for (let i = 0; i < this.size; i++) {
                    for (let j = 0; j < this.size; j++) {
                        let pos = i * this.size + j
                        this.yCoordinates[pos] = i * this.gridsizey
                        this.xCoordinates[pos] = j * this.gridsizex
                    }
                }
                break
            case 6:
                let distXh = this.gridsize
                let distYh = distXh * ...
                for (let i = 0; i < this.size; i++) {
                    for (let j = 0; j < this.size; j++) {
                        let pos = i*this.size+j
                        this.yCoordinates[pos] = i * distYh
                        this.xCoordinates[pos] = (j * distXh + i * (distXh / 2))
                        while ((this.xCoordinates[pos] - (this.size * distXh)) >= 0) {
                            this.xCoordinates[pos] -= (this.size * distXh)
                        }
                    }
                }
                break
        }
    }
}

以下是从该 OG 类创建的类以及函数。在完整的代码中,每个类中都有更多的函数(使用 Shape 类中的函数和数组),但就像函数一样,它们基本上是相同的。plotShapeplotShape

class Rectangle {
    constructor (options) {
        this.size = options.size
        this.gridsizex = options.gridsizex
        this.gridsizey = options.gridsizey
        this.rec = new Shape ({
            size: this.size,
            type: 4,
            gridsizex: this.gridsizex
            grdisizey: this.gridsizey
        })
        this.rec.createShape()
    }
    
    plotShape (plot) {
        plot.data = {
            xAxis: this.rec.xCoordinates,
            yAxis: this.rec.yCoordinates,
        }
    }
}


class Hexagon {
    constructor (options) {
        this.size = options.size
        this.gridsize = options.gridsize
        this.hex = new Shape ({
            size: this.size,
            type: 6,
            gridsize: this.gridsize
        })
        this.hex.createShape()
    }
    
    plotShape (plot) {
        plot.data = {
            xAxis: this.hex.xCoordinates,
            yAxis: this.hex.yCoordinates,
        }
    }
}


recShape = new Retangle({
    size: 6,
    gridsizex: 3,
    gridsizey: 2,
})

hexShape = new Hexagon ({
    size: 6,
    gridsize: 1,
})

function depiction(){
    recShape.plotShape(shapePlot)
    hexShape.plotShape(shapePlot)
}

我一直在尝试创建一个名为“Forms”的新类,在其中创建所有函数,然后将类“Rectangle”、“Hexagon”等扩展到类“Forms”。然后,这些子类可以一起使用所有这些函数,这样我就可以节省很多代码行。但是因为我在所有类中都以不同的方式称呼这个类“形状”,所以我不太确定该怎么做,因为我总是到达一个点,我意识到这是行不通的。另一种方法可能是使用静态方法,但是我仍然没有真正理解它们是如何工作的。

话虽如此,我没有代码可以展示以前的尝试,因为我总是在某一时刻意识到它不起作用。

JavaScript 扩展

评论

0赞 ii iml0sto1 9/14/2023
阅读 DRY 原则..但是,我在这里根本没有看到问题。
3赞 epascarello 9/14/2023
您担心在每节课中重复一行代码?你为什么不从基扩展类是有原因的吗?
0赞 trincot 9/14/2023
createShape 和 createGrid 一样吗?
0赞 Tobias Dräger 9/14/2023
@epascarello 这不仅仅是一行代码。代码片段仅显示 Rectangle 和 Hexagon 类中完全相同使用的十个函数中的一个(总共约 200 行)。关于你的另一个问题,直到阅读你的评论,我什至没有听说过关于JavaScript的“基础”。我手上的手册没有提到它。
0赞 Tobias Dräger 9/14/2023
@trincot 是的。很抱歉造成这种混乱。更正了这些错别字。

答:

1赞 trincot 9/14/2023 #1

您使用的是聚合模式,而此处的普通继承是更好的选择。这就是说六边形有形状和说六边形形状的区别。后者是继承。

与此相关,您不需要属性。这来自您创建的对象的原型,您可以测试而不是 .typehexShape instanceof HexagonhexShape.type == 6

因此,构造函数只需要一个 ,因此我不会将其作为对象传递 - 除非您有适用于所有形状的其他选项,否则这似乎有点矫枉过正。Shapesizeoption

您的代码似乎代表了大型代码库的点点滴滴,因此我将把相同的点滴修改为该模式:

class Shape {
    constructor(size) {
        this.size = size;
    }

    createGrid() {
        this.xCoordinates = new Float64Array(this.size * this.size);
        this.yCoordinates = new Float64Array(this.size * this.size);
    }

    plotGrid(plot) {
        plot.data = {
            xAxis: this.xCoordinates,
            yAxis: this.yCoordinates,
        }
        //...
    }
}

class Rectangle extends Shape {
    constructor (options) {
        super(options.size);
        this.gridsizex = options.gridsizex;
        this.gridsizey = options.gridsizey;
        this.createGrid();
    }
    createGrid() {
        super.createGrid();
        for (let i = 0; i < this.size; i++) {
            for (let j = 0; j < this.size; j++) {
                let pos = i * this.size + j
                this.yCoordinates[pos] = i * this.gridsizey
                this.xCoordinates[pos] = j * this.gridsizex
            }
        }
    }
}

class Hexagon extends Shape {
    constructor(options) {
        super(options.size);
        this.gridsize = options.gridsize;
        this.createGrid();
    }
    createGrid() {
        super.createGrid();
        let distXh = this.gridsize;
        let distYh = distXh /* ... */
        for (let i = 0; i < this.size; i++) {
            for (let j = 0; j < this.size; j++) {
                let pos = i*this.size+j;
                this.yCoordinates[pos] = i * distYh;
                this.xCoordinates[pos] = (j * distXh + i * (distXh / 2));
                while ((this.xCoordinates[pos] - (this.size * distXh)) >= 0) {
                    this.xCoordinates[pos] -= (this.size * distXh);
                }
            }
        }
    }
}

const recShape = new Rectangle({
    size: 6,
    gridsizex: 3,
    gridsizey: 2,
});

const hexShape = new Hexagon({
    size: 6,
    gridsize: 1,
});

function depiction(shapePlot) {
    recShape.plotGrid(shapePlot);
    hexShape.plotGrid(shapePlot);
}

评论

0赞 Tobias Dräger 9/14/2023
谢谢。这看起来不错。我很快就会尝试一下。
1赞 Tobias Dräger 9/15/2023
我首先用 Rectangle 类测试了它,它确实有效。尽管我必须将“this.createGrid”调用从 Shape 构造函数移动到 Rectangle 构造函数,否则我将首先在 Rectangle 构造函数中调用“this.createGrid”,然后定义“this.gridsizex”和“this.gridsizey”,这导致坐标数组被 NaN 填充。所以真的,非常感谢您的这个解决方案!
1赞 Tobias Dräger 9/15/2023
是的,计划这样做。昨天只是匆忙。它现在被标记为已接受。
0赞 Peter Seliger 9/19/2023
第一段已经值得投赞成票。