2016-06-01 28 views
0

Ich lese das POODR-Buch und es verwendet die alte Syntax für die Initialisierung mit Standardwerten. Ich möchte dasselbe mit der neuen Syntax implementieren.Ruby-Initialisierung mit Schlüsselwort args

class Gear 
    attr_reader :chainring, :cog, :wheel 
    def initialize(args) 
    @chainring = args.fetch(:chainring, 40) 
    @cog = args.fetch(:cog, 10) 
    @wheel = args[:wheel] 
    end 

    def gear_inches 
    ratio * diameter 
    end 

    def diameter 
    wheel * diameter 
    end 
end 

Gear.new(chainring: 52, cog: 11, wheel: Wheel.new(26,1.5)).gear_inches 

Wie würde das mit dem neuen Schlüsselwort args aussehen? Dies ist meine Schätzung unten, aber nicht sicher, ob es das gleiche für das Rad wie oben ergibt.

class Gear 
    attr_reader :chainring, :cog, :wheel 
    def initialize(chainring: 40, cog: 10, wheel:) #is this good here for wheel? 
    @chainring = chainring 
    @cog = cog 
    @wheel = wheel #is this good here for wheel? 
    end 

    ...... 
end 
+0

'Rad: Nil' wäre äquivalent – Stefan

Antwort

0

Ihr Beispiel mit Keywords Argumente ist auf die alte Art und Weise nicht gleichwertig, weil :wheel erforderlich sein wird, während in dem alten Code es nicht war.

Sie können Schlüsselwortarg nicht verwenden, wenn die Schlüsselwörter optional sein sollen.

+0

Agis, und wenn ich das mache, was Stefan im obigen Kommentar vorgeschlagen hat? –

1

Die wörtlichen äquivalent wäre dies:

class Gear 
    def initialize(**args) 
    @chainring = args.fetch(:chainring, 40) 
    @cog = args.fetch(:cog, 10) 
    @wheel = args[:wheel] 
    end 
end 

Der ursprüngliche Code beliebige Tasten erlaubt weitergegeben werden und ignoriert nur die, die es nicht, deshalb braucht, verwenden wir das ** ksplat zu ermöglichen willkürliche Argumente.

Wir konnten diesen Code zu diesem Refactoring:

class Gear 
    def initialize(chainring: 40, cog: 10, **args) 
    @chainring = chainring 
    @cog = cog 
    @wheel = args[:wheel] 
    end 
end 

Dies etwas besser liest. Aber es ist immer noch schlechtes Design: Warum erlaubt der Benutzer, beliebige Schlüssel zu übergeben? Es ist wahrscheinlich ein Fehler, wenn ein nicht verwendeter Schlüssel übergeben wird. Z.B. der Benutzer ruft Gear.new(cgo: 20) an, was eindeutig ein Tippfehler ist, aber statt einen Fehler zu erhalten, wird er im Hintergrund falsche Daten erhalten (ein cog Wert von 10).

class Gear 
    def initialize(chainring: 40, cog: 10, wheel: nil) 
    @chainring = chainring 
    @cog = cog 
    @wheel = wheel 
    end 
end 

Dies entspricht der Verhalten des ursprünglichen Codes bestimmt, würde ich raten. Es verhält sich anders, weil es keine willkürlichen Schlüssel erlaubt, aber ich denke, das macht sowieso keinen Sinn. Also, obwohl nicht gleichwertig, ist es wohl besser.

Es gibt jedoch immer noch ein Problem (das gibt es auch im Originalcode): Es ist nicht möglich, wheel zu übergeben, wodurch wheel endet nil. Jedoch wird wheel bedingungslos verwendet (z. B. in diameter), was bedeutet, dass es zur Laufzeit hochfährt, wenn wheelnil ist. So ist es besser, zu verlangen wheel weitergegeben werden:

class Gear 
    def initialize(chainring: 40, cog: 10, wheel:) 
    @chainring = chainring 
    @cog = cog 
    @wheel = wheel 
    end 
end 

Welche ist natürlich genau das, was Sie hatten. Dies ist nicht Äquivalent in Verhalten, aber ich würde es ague es ist entspricht in Absicht und ist wohl viel besser und richtiger.

+0

Jorg, danke für die ausführliche Antwort! Ich habe jedoch zwei Fragen: 1. Könntest du mir bitte sagen, dass du im letzten Beispiel '@chainring = args [: chainring]' anstelle von '@chainring = chainring' verwendest (Frage gilt auch für @cog und @wheel) ? 2. Wenn ich also das Rad optional machen möchte, kann ich einfach 'wheel: nil' in den Argumenten verwenden, aber wenn ich es machen will, dann benutze' wheel: 'im Argument? –