Սկիզբ » Ուսումնական նյութեր » Ծրագրավորում » Ծրագրավորման լեզուներ » Go » Go. Օբյեկտներին կողմնորոշված ծրագրավորում

Go. Օբյեկտներին կողմնորոշված ծրագրավորում

| Նոյեմբեր 1, 2012 | 2 Մեկնաբանություններ |

Արդեն դասական դարձած օրինակով նկարագրեմ, թե ինչպես է Go լեզուն հնարավորություն տալիս ծրագրավորել օբյեկտներին կողմնորոշված մոտեցմամբ։ Դիտարկենք երկչափ պատկերների վերացական հասկացությունը՝ իր կետ, շրջան և ուղղանկյուն կոնկրետացումներով։ Ենթադրենք պատկերների համար կարելի է հաշվել նրանց մակերեսը, պարագիծը և ստանալ նրանց տեքստային ներկայացումը։

Բոլոր այս հասկացությունները իրականացվելու են shapes փաթեթում։ Ստեղծենք shapes.go ֆայլը և նրա սկզբում հայտարարենք փաթեթը։

package shapes

Շրջանագծի մակերեսն ու պարագիծը հաշվելու համար հարկավոր է լինելու Pi հաստատունը math փաթեթից, իսկ պատկերների տեքստային ներկայացումները կառուցելու համար Sprintf ֆունկցիան՝ fmt փաթեթից։ Ներմուծենք այս երկու փաթեփները։

import (
    "math"
    "fmt"
)

Վերևում նշվեց, որ պատկերների համար կարող ենք հաշվել մակերեսը (area), պարագիծը (perimeter) և տեքստային ներկայացումը (to string)։ Սահմանենք Shape ինտերֆեյսը, որը խմբավորում է այս գործողությունները մոդելավորող մեթոդները։

type Shape interface {
    Area() float64 // մակերեսը որպես 64 բիթանոց իրական թիվ
    Perimeter() float64 // պարագիծը որպես 64 բիթանոց իրական թիվ
    ToString() string // տեքստային ներկայացումը որպես տող
}

Եթե փաթեթում սահմանված իդենտիֆիկատորը, լինի դա տիպի, ֆունկցիայի, մեթոդի, փոփոխականի կամ այլ անուն, սկսվում է մեծատառով, ապա այն համարվում է ընդհանուր հասանելի (public), հակառակ դեպքում, երբ անունը սկսվում է փոքրատառով կամ ընդգծման գծի նշանով, ապա այն համարվում է ներքին (private):

Սկսենք ամենապարզ պատկերի՝ կետի սահմանումից։ Go լեզվում չկա դաս (class) հասկացությունը, որն իր մեջ կխմբավորեր մեթոդներն ու դաշտերը։ Բայց բաղադրյալ տիպեր սահմանելու համար կա ստրուկտուրա։ Կետը կսահմանենք որպես ստրուկտուրա՝ x և y կոորդինատների դաշտերով։

type Point struct {
    x, y float64 // կոորդինատները որպես իրական թվեր
}

Չկա նաև կոնստրուկտոր։ Մենք պետք է սահմանենք մի ֆունկցիա, օրինակ, NewPoint անունով, որը կստեղծի նոր Point տիպի օբյեկտ, կարժեքավորի նրա դաշտերը և կվերադարձնի այդ նոր ստեղծված օբյեկտի ցուցիչը։

func NewPoint(cx, cy float64) *Point {
    p := new(Point)
    p.x, p.y = cx, cy
    return p
}

new ներդրված ֆունկցիան ստեղծում և բերադարձնում է տրված տիպի նոր օբյեկտ։ p ցուցիչի x և y դաշտերն արժեքավորվում են զուգահեռ վերագրման հրամանով։

Ստրուկտուրան պարունակում է միայն դաշտերի նկարագրությունը։ Մեթոդները, որոնց տեսքը թվարկված է Shape ինտերֆեյսում, որևէ կերպ կապված չեն ստրուկտուրաներին։ Ի տարբերություն սովորական ֆունկցիաների, մեթոդներն ունեն ևս մի պարամետր՝ receiver, որը գրվում է մեթդի անունից առաջ և ցույց է տալիս, թե ինչ տիպի օբյեկտի համար պետք է կանչվի տվյալ իրականացումը։ Կետի համար Area և Perimeter մեթոդների իրականցումներն ունեն ահա այսպիսի տեսք․

func (p *Point) Area() float64 {
    // կետի մակերեսը զրո է
    return 0.0
}
func (p *Point) Perimeter() float64 {
    // կետի պարագիծը զրո է
   return 0.0
}

Ես ընտրել եմ օբյեկտների տեքստային ներկայացման մի եղանակ, որն ընդունված է Common Lisp լեզվում ստրուկտուրաների նմուշների ներկայացման համար։ Օրինակ, (3,4) կետի համար օբյեկտի տեքստային ներկայացումը կունենա #S(POINT :X 3 :Y 4) տեսքը։

func (p *Point) ToString() string {
    return fmt.Sprintf("#S(POINT :X %f :Y %f)", p.x, p.y)
}

Շրջանագիծը մոդելավորող ստրուկտուրան ունի երկու դաշտ՝ կենտրոնը, որը Point տիպի ցուցիչ է, և շառավիղը, որը իրական թիվ է։

type Circle struct {
    center *Point // ցուցիչ է
    radius float64 // իրական թիվ է
}

Սահմանենք կոնստրուկտոր ֆունկցիա նաև Circle տիպի օբյեկտների համար։

func NewCircle(c *Point, r float64) *Circle {
    cr := Circle{c, r}
    return &cr
}

Այս ֆունկցիայում կիրառված է օբյեկտի ստեղծման և դաշտերի արժեքավորման մի այլ եղանակ․ Տիպի անունից հետո, ձևավոր փակագծերում թվարկված են արժեքներ, որոնք հերթականորեն վերագրվում են ստրուկտուրայի դաշտերին։ & նիշը հնարավորություն է տալիս վերցնել օբյեկտի հասցեն։

Այժմ նույն մեթոդներն իրականացնենք *Circle տիպի receiver-ների համար։ Շրջանի մակերեսը որոշվում է 3.14*r2 բանաձևով։ թիվը math փաթեթում ներկայացված է որպես Pi հաստատուն։

func (c *Circle) Area() float64 {
    return math.Pi * c.radius * c.radius
}

Պարագիծը որոշվում է 2*3.14*r բանաձևով։

func (c *Circle) Perimeter() float64 {
    return 2.0 * math.Pi * c.radius
}

Տեքստային ներկայացումը կառուցելու ժամանակ շրջանի կենտրոնը ներկայացնող կետի տեսքը ստանանք կանչելով center դաշտի ToString մեթոդը։

func (c *Circle) ToString() string {
    str := fmt.Sprintf("#S(CIRCLE :CENTER ")
    str += c.center.ToString() // կենտրոնի տեքստային ներկայացումը
    str += fmt.Sprintf(" :RADIUS %f)", c.radius)
    return str
}

Եվ վերջապես, սահմանենք Rectangle տիպը և իրականացնենք մեթոդները նրա համար։

type Rectangle struct {
    origin *Point
    corner *Point
}

func NewRectangle(or, co *Point) *Rectangle {
    return &Rectangle{origin: or, corner: co}
}
func (r *Rectangle) Area() float64 {
    dx := r.corner.x - r.origin.x
    dy := r.corner.y - r.origin.y
    return dx * dy
}

func (r *Rectangle) Perimeter() float64 {
    dx := r.corner.x - r.origin.x
    dy := r.corner.y - r.origin.y
    return 2.0 * (dx + dy)
}

func (r *Rectangle) ToString() string {
    sor := r.origin.ToString()
    sco := r.corner.ToString()
    return fmt.Sprintf("#S(RECTANGLE :ORIGIN %s :CORNER %s)", sor, sco)
}

 

Այս վիճակում Point, Circle և Rectangle ստրուկտուրանիերի համար իրականացրեցինք այն բոլոր մեթոդները, որոնք թվարկված են Shape ինտերֆեյսում։ Սա հնարավորություն է տալիս այդ նշված տիպով օբյեկտների համար օգտվել պոլիմորֆիզմի հնարավորություններից։ Տեսնելու համար, թե դա ինչպես է աշխատում, գրենք մի քանի օրինակներ։

func main() {
    p0 := shapes.NewPoint(0, 0)
    p1 := shapes.NewPoint(3, 4)

    c0 := shapes.NewCircle(p0, 5)

    r0 := shapes.NewRectangle(p0, p1)

    sh := [4]shapes.Shape{p0, p1, c0, r0}
    for i := 0; i < 4; i++ {
        fmt.Println("~ ~ ~")
        fmt.Println(sh[i].ToString())
        fmt.Println("Area =", sh[i].Area())
        fmt.Println("Perimeter =", sh[i].Perimeter())
    }
}

main ֆունկցիայի կատարվելուց հետո կստանանք հետևյալ արդյունքը, որը լիովին համընկնում է մեր սպասելիքներին։

~ ~ ~
#S(POINT :X 0.000000 :Y 0.000000)
Area = 0
Perimeter = 0
~ ~ ~
#S(POINT :X 3.000000 :Y 4.000000)
Area = 0
Perimeter = 0
~ ~ ~
#S(CIRCLE :CENTER #S(POINT :X 0.000000 :Y 0.000000) :RADIUS 5.000000)
Area = 78.53981633974483
Perimeter = 31.41592653589793
~ ~ ~
#S(RECTANGLE :ORIGIN #S(POINT :X 0.000000 :Y 0.000000) :CORNER #S(POINT :X 3.000000 :Y 4.000000))
Area = 12
Perimeter = 14

Հղումներ

Go. Օբյեկտներին կողմնորոշված ծրագրավորում, 10.0 out of 10 based on 7 ratings

Նշագրեր: , ,

Բաժին: Go

Կիսվել , տարածել , պահպանել

VN:F [1.9.20_1166]
Rating: 10.0/10 (7 votes cast)

Մեկնաբանություններ (2)

Թրեքբեք հղում | Մեկնաբանությունների RSS ժապավեն

  1. այս մոդելը գրեթե կրկնում է Օբերոն֊2 լեզվի օկծ իրականացումը։
    եթե չեք նայել, խորհուրդ եմ տալիս փորձարկել։ որպես կոմպիլյատոր խորհուրդ կտամ ooc֊ն։
    առհասարակ Ռոբ Փայքի այլ պրոեկտներն էլ՝ Պլան ինը ու Ինֆերնոն, acme խմբագրիչը Օբերոն համակարգի ու TUI (textual user interface) ֊ի ակնհայտ ազդեցության տակ են։

    • Երբ ուսումնասիրում էի C++, Java, Smalltalk և Oberon-2 կամ Component Pascal լեզուներում իրականացված ՕՕԾ մեխանիզմները, ինձ ավելի հարմար ու էլեգանտ թվաց հենց Oberon-2-ի տարբերակը։ ՈՒ, երբ քչփորում էի Go լեզուն, հենց պատճառներից մեկը դա էր, որ որոշեցի հիմնավորապես “կպնել” Go-ի ուսումնասիրմանը։

      Ի դեպ, Վիրտի լեզուների շարքի ամեն մի ներկայացուցիչ առանձնանում է իր առավել պարզությամբ ու թվացյալ բարդ գաղափարներ պարզ ու գեղեցիկ մոդելավորմամբ (իմ կարծիքով 🙂 ):

Մեկնաբանեք

Կհաստատվեն միայն մեսրոպատառ հայերենով գրած մեկնաբանությունները

195