面向?qū)ο缶幊虒W(xué)習(xí)筆記

1.面向?qū)ο缶幊?

1.0 為何要有面向?qū)ο缶幊?

很早之前程序員就發(fā)現(xiàn),隨著軟件的日趨復(fù)雜與龐大,維護(hù)往往變成了一個很棘手的問題.因為貫穿整個程序的依賴(dependencies),在一個程序中一個很小的改變就可能引起如同漣漪般擴散的偏差(errors).

而面向?qū)ο缶幊陶菫榱私鉀Q這個問題而誕生的.

1.1 何為面向?qū)ο缶幊?

面向?qū)ο缶幊?Object oriented programming)是一種基于對象的編程范型.在面向?qū)ο缶幊陶Z言中,一切均是對象.

1.2 對象(object)的定義:

對象是指一個具體的事物.它有具體的行為(behaviors),有具體的屬性(states).有時可以對應(yīng)現(xiàn)實世界的事物,例如小狗聰聰,貓咪毛毛等.

1.3 類(class)的定義:

定義:

類相當(dāng)于一副藍(lán)圖,定義了一類事物的抽象特點. 例如,"狗"這個類會包含狗的一切基礎(chǔ)特征,即所有“狗”都共有的特征或行為,例如它的孕育、毛皮顏色和吠叫的能力。

作用:

這樣創(chuàng)建一類具有相同行為與共通的屬性的對象時,先創(chuàng)建一個這樣的一個類,再用這個類去定義具體的對象,就可以少寫很多代碼.

1.4 面向?qū)ο缶幊痰娜笾е?

  • 封裝性(Encapsulation)

限定只有特定的類的對象才能調(diào)用特定類的方法,并且隱藏了方法的具體執(zhí)行步驟.

示例:

/* 一個面向過程的程序會這樣寫: */
定義萊絲
萊絲.設(shè)置音調(diào)(5)
萊絲.吸氣()
萊絲.吐氣()

/* 而當(dāng)狗的吠叫被封裝到類中,任何人都可以簡單地使用: */
定義萊絲是狗
萊絲.吠叫()
  • 繼承(inheritance)

在某些情況下一個類會有子類,子類比父類更加具體.例如,“狗”這個類可能會有它的子類"牧羊犬"和"吉娃娃".子類會繼承父類的屬性和行為,并且包含它自己的.假設(shè)"狗"這個類有一個方法(行為)叫做“吠叫()”和一個屬性叫做“毛皮顏色”。它的子類(前例中的牧羊犬和吉娃娃犬)會繼承這些成員。

例如:

類牧羊犬:繼承狗

定義萊絲是牧羊犬
萊絲.吠叫()    /* 注意這里調(diào)用的是狗這個類的吠叫方法。*/
  • 多態(tài)(Polymorphism)

多態(tài)(Polymorphism)是一個專業(yè)術(shù)語,意指"許多形態(tài)"("many shapes").更具體來說是同一種操作被用不同方式執(zhí)行.

例如,狗和雞都有“叫()”這一方法,但是調(diào)用狗的“叫()”,狗會吠叫;調(diào)用雞的“叫()”,雞則會啼叫。 我們將它體現(xiàn)在偽代碼上:

類狗
開始
   公有成員:
       叫()
       開始
          吠叫()
       結(jié)束
結(jié)束

類雞
開始
   公有成員:
       叫()
       開始
          啼叫()
       結(jié)束
結(jié)束

定義萊絲是狗
定義魯斯特是雞
萊絲.叫()
魯斯特.叫()

這樣同樣做出叫這個動作,萊絲與魯斯特的實際行為會大相徑庭.

2. 關(guān)于對象(object)

2.1 initialize object:

語法:

Classname.new

示例:

  • 不帶參數(shù):
--- initialize class called GoodDog ---
class GoodDog 
    
end 

--- initialize object ----
sparky=GoodDog.new
  • 帶參數(shù):
--- initialize class called GoodDog ---
class GoodDog 
    def initialize(name,color)
        @name = name
        @color = color
    end 
end 

--- initialize object ----

sparky=GoodDog.new("sparky","white")

2.2 instance variable

2.2.1 作用:

記錄對象的屬性(keep track of states of object)

2.2.2 定義語法:

  • 以"@"符號開頭
  • 后面跟著表示對象屬性的單詞,并且使用小寫字母

示例:

class GoodDog 
    def initialize(name,color)
        @name = name
        @color = color
    end 
end 

sparky = GoodDog.new("sparky","white")

2.2.3 instance variable的存取:

2.2.3.1 如何進(jìn)行存取:

背景問題1:

如何輸出@name的值

以上面代碼為例,雖然有了instance variable,但是如果我們想要 輸出 sparky 的name,那么應(yīng)該怎么辦?

sparky.name # => NoMethodError: undefined method `name' for #<GoodDog:0x007f91821239d0
  @name="Sparky">

上面的錯誤提示告訴我們我們沒有定義一個叫做name 的method,也就是說我們需要定義一個方法來存放@name的值,來方便我們輸出.

這似乎是說"object."后面只能跟method,而不能跟variable

解決方案:

class GoodDog 
    def initialize(name,color)
        @name = name
        @color = color
    end 
    
--- add getter_method ---   

    def get_name
        @name
    end
end 

sparky = GoodDog.new("sparky","white")

這樣我們就可以輸出sparky的名字了:

puts sparky.get_name # => sparky

背景問題2:

現(xiàn)在已經(jīng)有了getter method,

但如何改變name的值?

解決方案:

class GoodDog 
    def initialize(name,color)
        @name = name
        @color = color
    end 
    
--- add getter_method ---   

    def get_name
        @name
    end

--- add setter_method ---
    
    def set_name=(name)
        @name = name 
    end
end 

sparky = GoodDog.new("sparky","white")

現(xiàn)在運行下面的代碼:

sparky.set_name = "spartacus"
puts sparky.get_name    #=> spartacus

就會發(fā)現(xiàn)name的值改變了.

2.2.3.2 對上述代碼進(jìn)行重構(gòu):
  • 重構(gòu)的原因:

Rubyist習(xí)慣使用相同的名稱來命名instance variable的getter method 和setter method .

  • 重構(gòu)后的代碼:

統(tǒng)一使用name來命名getter method 和setter method.

class GoodDog
  def initialize(name)
    @name = name
  end
  
  def name                      # This was renamed from "get_name"
    @name
  end
  
  def name=(n)                  # This was renamed from "set_name="
    @name = n
  end
end

sparky = GoodDog.new("Sparky")
puts sparky.speak
puts sparky.name            # => "sparky"
sparky.name = "Spartacus"
puts sparky.name            # => "Spartacus"
2.2.3.3 對上述代碼進(jìn)行再次重構(gòu)(attr_*):
  • 重構(gòu)的原因:

上述代碼占用的空間太多了,只有一個instance variable還好,若是有多個呢?例如height / weight.這樣就太麻煩了.

  • 解決方案:

Ruby內(nèi)置了一套方案來解決上述問題.

attr_accessor method 可以自動的幫助我們產(chǎn)生和上面一樣的getter / setter metods.

class GoodDog
    attr_accessor :name         # using attr_accessor method 
    
    def initialize(name)
      @name = name
    end
    
end

  sparky = GoodDog.new("Sparky")
  puts sparky.speak
  puts sparky.name            # => "Sparky"
  sparky.name = "Spartacus"
  puts sparky.name            # => "Spartacus"

這樣寫就會簡潔/方便很多.

  • 含有多個instance variable的寫法:

    attr_accessor :name, :height, :weight
    
2.2.3.4 其他兩種attr_* method:
  • 只想要getter method,而不需要setter method :

    attr_reader

  • 只想要setter method ,而不想要 getter method:

attr_writer

2.2.4 在class內(nèi)部使用getter / setter method:

2.2.4.1在class內(nèi)部使用getter method 替換 instance variable:
  • 原因:

如果我們有一個social_security_numbers(用@ssn表示),我們并不想展示所有的數(shù)字,只想展示后四位,那么可以這樣寫:

"****-****-" + @ssn.split("-").last

如果我們需要多次使用到這行代碼,與其多次重復(fù)寫入,不如寫一個method將這行代碼封裝起來.

另外原本的getter mehod 不能讓別人直接調(diào)用,所以不如直接使用getter method 來封裝這行代碼:

def ssn
    "****-****-" + @ssn.split("-").last 
end     
  • 示例:

    class Account
      
      def initialize(name,ssn)
          @name = name
          @ssn =ssn
      end 
      
      def ssn
          "****-****-" + @ssn.split("-").last 
        end   
      
      def ssn_hint
          "Your ssn is #{ssn}"        #  using ssn instead of @ssn
      end
      
    end   
    
2.2.4.2在class內(nèi)部使用setter method:
  • 原因:

如實在GoodDog class中有多個instance variable,而我們定義一個方法(change_info)用來同時改變著多變量的值:

def change_info(n,h,w)
    @name = n
    @height = h 
    @weight = w
end 

為了與上面的在class內(nèi)部使用getter method保持一致(consistence),從而使用setter_method來進(jìn)行替換.

  • 失敗的嘗試:

根據(jù)上面的思路我們對change_info這個method進(jìn)行了修改.

class GoodDog
    attr_accessor :name, :height, :weight
    
    def initialize(n, h, w)
      @name = n
      @height = h
      @weight = w
    end
    
    def speak
      "#{name} says arf!"
    end
    
    def change_info(n, h, w)        # try using setter method
      name = n
      height = h
      weight = w
    end
    
    def info
      "#{name} weighs #{weight} and is #{height} tall."
     end

但是當(dāng)我們進(jìn)行檢測時,卻發(fā)現(xiàn)變量的值并沒有改變.

sparky = GoodDog.new('Sparky', '12 inches', '10 lbs')

puts sparky.info      # => Sparky weighs 10 lbs and is 12 inches tall.

sparky.change_info('Spartacus', '24 inches', '45 lbs')

puts sparky.info      # => Spartacus weighs 45 lbs and is 24 inches tall.
  • 失敗的原因:

    在上述代碼中Ruby誤以為我們是想創(chuàng)建新的變量,分別叫name/height/weight了.

    所以就會發(fā)現(xiàn)@name等變量并沒有改變.

  • 使用self method進(jìn)行修正:

    def change_info(n, h, w)        # using self method
      self.name = n
      self.height = h
      self.weight = w
    end
  • 為了保持一致,統(tǒng)一將調(diào)用getter method 的地方加上self.
def info
    "#{self.name} weighs #{self.weight} and is #{self.height} tall."
end
  • 最終結(jié)果是形成一個慣例(convention):
  • class 內(nèi),用到instance variable的地方使用getter method ;
  • class內(nèi),除setter method以外,需要改變instance variable值的地方統(tǒng)一使用setter method;
  • 在class內(nèi)使用到getter / setter method 的地方都使用self method

3.關(guān)于類(class)

3.1 class variable:

3.1.1 作用:

不知道怎么描述,所以通過下面的代碼進(jìn)行感受.

3.1.2 定義方法:

  • 語法:
  • 使用"@@"作為開頭;
  • 緊跟著是能夠描述想要記錄屬性的小寫的英文單詞.
  • 示例:
class GoodDog
  @@number_of_dogs = 0
  
  def initialize
    @@number_of_dogs += 1
  end
  
end

3.2 類方法(class method):

3.2.1 作用:
3.2.2 定義方法:
  • 語法:
  • 使用self method;
  • 用小寫單詞命名.
  • 示例:
class GoodDog
  @@number_of_dogs = 0

  def initialize
    @@number_of_dogs += 1
  end

  def self.total_number_of_dogs
    @@number_of_dogs
  end 
end

puts GoodDog.total_number_of_dogs   # => 0
dog1 = GoodDog.new
dog2 = GoodDog.new
puts GoodDog.total_number_of_dogs   # => 2

3.3 常量(constants):

其實和class并沒有什么關(guān)系.

3.3.1 為什么要有常量:

有時候我們無論如何都不想要定義的量的值改變,這時就使用常量.

3.3.2 常量的定義方法:
  • 語法:
  • 使用首字母大寫的英語單詞;
  • Rubyist習(xí)慣上將常量的所有字母都大寫.
  • 示例:
class GoodDog
    DOG_YEARS = 7                   # constants
    
    attr_accessor :name, :age
    
    def initialize(n, a)
      self.name = n
      self.age  = a * DOG_YEARS
    end 
end

sparky = GoodDog.new("Sparky", 4)
puts sparky.age

3.4 The to_s method:

這部分其實和class也沒有什么關(guān)系.

3.4.1 自動調(diào)用to_s method的兩種情況 :
  • puts method 自動調(diào)用to_method.

    示例:

    ---這里輸出的結(jié)果是:前面是sparky這個對象對應(yīng)的class(GoodDog),緊跟的一串?dāng)?shù)字/字母是這個是這個對象的ID編碼---
    
    puts sparky      # => #<GoodDog:0x007fe542323320>
    

    puts sparky 等價于puts sparky.to_s

  • 字符串插值(string interpolation)自動調(diào)用to_s method:

    • 字符串插值(string interpolation)就是將常量或者變量插入字符串中.

    示例:

    irb :001 > arr = [1, 2, 3]
      => [1, 2, 3]
      irb :002 > x = 5
      => 5
      irb :003 > "The #{arr} array doesn't include #{x}."
      => The [1, 2, 3] array doesn't include 5.
    

    在這里字符串插值自動的調(diào)用to_s method,然后將arr 和 x 兩個變量轉(zhuǎn)換成了對應(yīng)的值,然后與字符串結(jié)合在了一起.

3.4.2 了解to_s method的自動調(diào)用的益處:

雖然當(dāng)前感覺了解to_s method是無關(guān)緊要的,但這卻會在日后幫助我們更好的讀寫oo code.

3.5 進(jìn)一步了解self method

上面有兩處使用了self method:

  • 告訴Ruby我們想要調(diào)用的是setter method,而不是創(chuàng)建新的變量;
  • 使用self method幫助定義class method.

那么self究竟是什么?

3.5.1 self指代object:

代碼示例

class GoodDog
    # ... rest of code omitted for brevity
    def what_is_self
      self
end end
sparky = GoodDog.new('Sparky', '12 inches', '10 lbs')
  p sparky.what_is_self
   # => #<GoodDog:0x007f83ac062b38 @name="Sparky", @height="12 inches",
  @weight="10 lbs">

通過上述代碼我們可以發(fā)現(xiàn)self指代的是object(sparky)

3.5.2 self指代class:

代碼示例:

class GoodDog
    # ... rest of code omitted for brevity
    puts self
end
irb :001 > GoodDog
  => GoodDog

通過上面我們得出self指代的是GoodDog這個class.

3.5.3 如何判斷self指代什么:
  1. self,insideofaninstancemethod,referencestheinstance(object)thatcalledthemethod - the calling object. Therefore, self.weight= is the same as sparky.weight= ,in our example.
  2. self,outsideofaninstancemethod,referencestheclassandcanbeusedtodefineclass methods. Therefore, def self.name=(n) is the same as def GoodDog.name=(n) ,in our example.

4. 繼承(inheritance)

4.0 繼承的對象:

繼承的東西是superclass中的behavior.

4.1 繼承的作用:

通過繼承能夠?qū)崿F(xiàn)代碼復(fù)用,從而達(dá)到以下好處:

  • 除去寫重復(fù)代碼的麻煩;
  • 方便debug.

4.1 繼承的兩種方式:

  • class inheritance
  • mixing in module

4.2 class inheritance:

4.2.1 語法:

使用 <符號去標(biāo)記繼承方向.

示例:

class Animal
  def speak
    "Hello!" 
  end
end

class GoodDog < Animal          # 標(biāo)記GoodDog從Animal繼承behavior
end

class Cat < Animal
end

sparky = GoodDog.new
paws = Cat.new
puts sparky.speak           # => Hello!
puts paws.speak             # => Hello!

4.2.2 繼承behavior的overring

當(dāng)subclass中有與superclass中想相同的method時,subclass的object調(diào)用的就是subclass中的method.

示例:

class Animal
    def speak
        "Hello!"
    end
end

class GoodDog < Animal

    attr_accessor :name
    
    def initialize(n)
      self.name = n
    end
    
    def speak
      "#{self.name} says arf!"
    end 
end

class Cat < Animal
end

sparky = GoodDog.new("Sparky")
paws = Cat.new
puts sparky.speak           # => Sparky says arf!
puts paws.speak             # => Hello!

4.3 super

4.3.1 作用

在subclass中調(diào)用superclass中與instance method同名method.

示例:

class Animal
    def speak
        "Hello!" 
    end
end

class GoodDog < Animal
    def speak
      super + " from GoodDog class"
    end
end

sparky = GoodDog.new
sparky.speak             # => "Hello! from GoodDog class"
4.3.2調(diào)用super的三種狀況:
  1. 不含參數(shù):
class Animal
    def speak
        "Hello!" 
    end
end

class GoodDog < Animal
    def speak
      super + " from GoodDog class"
    end
end

sparky = GoodDog.new
sparky.speak             # => "Hello! from GoodDog class"
  1. 含參數(shù),但是不指定:
class Animal
    attr_accessor :name
    
    def initialize(name)
       @name = name
    end 
end

class GoodDog < Animal
    def initialize(color)
      super
      @color = color
    end
end

---這里因為使用了super 所以初始化object的時候調(diào)用了Animal中的initialze method,從而導(dǎo)致bruno多了一個屬性--name ---

bruno = GoodDog.new("brown")        # => #<GoodDog:0x007fb40b1e6718,@color="brown", @name="brown">
  1. 指定參數(shù):
class BadDog < Animal
    def initialize(age, name)
        super(name)
        @age = age 
    end
end
    
BadDog.new(2, "bear")           # => #<BadDog:0x007fb40b2beb68 @age=2,@name="bear">

4.4 Mixing in module

4.4.1 為什么要有mixing in module:

[圖片上傳失敗...(image-614c12-1510277893483)]

已上圖為例,如實Cat 與Dog有相同的behavior,這個時候我們就可以將它提取出來,放在Mammal中,通過繼承來使用.

那么問題來了,Dog與Fish也有相同的behavior—swim,這個時候顯然不能將對應(yīng)的method提取出來放到Mammal或者是Animal中(因為Cat不可以swim).解決方案就是使用Mixing in module .

4.4.2 mixing in module的思路

就是將兩個或者多個無法通過繼承來dry up 的code 封裝到一個容器中,然后讓這些class調(diào)用這個容器中的內(nèi)容.

具體來說是這樣.將Fish與Dog都有的behavior(swim)用Swimmable這個module進(jìn)行封裝,然后讓Fish與Dog進(jìn)行調(diào)用.

4.4.3 mixing in module 的定義:

示例:

module Swimmable
    def swim
        "I'm swim."
    end 
end 

解釋:

  • 使用首字母大寫的單詞;
  • rubyist 習(xí)慣上將單詞以able作為后綴.
4.4.4 mixing in module 的使用:
module Swimmable
  def swim
    "I'm swimming!"
  end
end

class Animal; end

class Fish < Animal
  include Swimmable     # mixing in Swimmable module
end

class Mammal < Animal
end

class Cat < Mammal
end

class Dog < Mammal
  include Swimmable     # mixing in Swimmable module
end

語法:

include modulename

5.其他:

5.1 Method lookup path:

5.1.1 定義:

object在調(diào)用方法(method)時,是按照一定順序進(jìn)行的,這個順序就叫method loopup path.

5.1.2 知道m(xù)ethod lookup path的作用:

當(dāng)我們研究一個較大的項目時,可能會困惑于那些方法是哪來的.但是若是知道了method lookup path,便能夠較好的理解那些方法是在哪兒,以及是如何組織的.

5.1.3 使用ancestors查詢method lookup path:

以下述代碼為例,如何才能知道Animal的object的method loopup path呢?

module Walkable
    def walk
      "I'm walking."
    end
end

module Swimmable
    def swim
      "I'm swimming."
    end
end

module Climbable
    def climb
      "I'm climbing."
    end
end

class Animal
    include Walkable
    
    def speak
      "I'm an animal, and I speak!"
    end 
end

使用ancestors method :

puts "---Animal method lookup---"
  puts Animal.ancestors

結(jié)果:

--- Animal method lookup ---
Animal
Walkable
Object
Kernel
BasicObject

5.1.4 method lookup path:

順序:

  • 在初始化對象的類中查找
  • 在該對象的module中查找(按照mixing進(jìn)的module的順序,進(jìn)行倒序查找)
  • 在該類的父類中查找

示例:

module Walkable
    def walk
      "I'm walking."
    end
end

module Swimmable
    def swim
      "I'm swimming."
    end
end

module Climbable
    def climb
      "I'm climbing."
    end
end

class Animal
    include Walkable
    
    def speak
      "I'm an animal, and I speak!"
    end 
end

class GoodDog < Animal
    include Swimmable
    include Climbable
end

puts "---GoodDog method lookup---"
puts GoodDog.ancestors

輸出結(jié)果:

---GoodDog method lookup path ---
GoodDog
Climbable
Swimmable
Animal
Walkable
Object
Kernel
BasicObject

5.2 module的另外兩種用法:

1.用于namespacing;

2.作為container of methods

5.2.1 用于namespacing:

作用:

  • 將同類型的class歸類放在一起;
  • 區(qū)分具有相同名字的class

定義方法:

module Mammal
    class Dog
      def speak(sound)
        p "#{sound}"
      end 
    end
    
    class Cat
      def say_name(name)
        p "#{name}"
      end
    end 
end

如何使用module中的class初始化對象:

buddy = Mammal::Dog.new
kitty = Mammal::Cat.new
buddy.speak('Arf!')           # => "Arf!"
kitty.say_name('kitty')       # => "kitty"
5.2.2 作為container of methods (module methods)

定義方法:

module Mammal
    ...
    def self.some_out_of_place_method(num)
      num ** 2
    end 
end

調(diào)用方法:

  • 法一:
value = Mammal.some_out_of_place_method(4)
  • 法二:
value = Mammal::some_out_of_place_method(4)

5.3 私有/公共/保護(hù)方法(private/public/protected):

5.3.1 私有方法(private method)

作用:

有時候我們只想讓某個方法在class內(nèi)部發(fā)生作用,而不再外部被調(diào)用,這個時候就使用private method.

定義方法:

使用保留字:private

class GoodDog
  DOG_YEARS = 7
  
   attr_accessor :name, :age
   
   def initialize(n, a)
      self.name = n
      self.age = a
    end
    
    private             # method following "private is pirvate method
    
    def human_years
      age * DOG_YEARS
    end 
end

sparky = GoodDog.new("Sparky", 4)
sparky.human_years

說明:

私有方法(private method)只能在instance method中被調(diào)用,且是直接調(diào)用不能用self method.

即使是objectname.privatemethod的形式也不行.

5.3.2 保護(hù)方法(protected method)

作用:

有時候我們想要在instance method中使用self.privatemethod或者objectname.privatemethod,的形式,但是有不想外界調(diào)用,這是就使用protected method.

語法:

使用保留字:protected

class Animal

    def a_public_method
      "Will this work? " + self.a_protected_method
    end

    protected
    
    def a_protected_method
      "Yes, I'm protected!"
    end 
end

class Student
      def initialize(name, grade)
        @name = name
        @grade = grade
      end
      
      def better_grade_than?(other_student)
        grade > other_student.grade
      end
      
      protected
      
      def grade
        @grade
      end 
end

joe = Student.new("Joe", 90)
bob = Student.new("Bob", 84)
puts "Well done!" if joe.better_grade_than?(bob)

5.4 偶發(fā)的方法重寫(accidental method overrding)

5.4.1 產(chǎn)生原因:

因為所有自己創(chuàng)建的類都繼承自class Object,這就導(dǎo)致當(dāng)有些method與Object中的method同名時,發(fā)生method overring.

示例:

例如:Object的send method可以調(diào)用某個方法,但是若被重寫了,就會出問題.

class Child
    def say_hi
      p "Hi from Child."
    end
    
    def send
      p "send from Child..."
    end 
end

lad = Child.new
lad.send :say_hi

報錯:

ArgumentError: wrong number of arguments (1 for 0)
from (pry):12:in `send'
5.4.2 啟示:

要熟知一些常見的Object methods,避免發(fā)生重寫(overrding),否則會對應(yīng)用造成災(zāi)難性的后果.

參考資料:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,041評論 0 9
  • 13.1類 類聲明與函數(shù)聲明很相似,頭一行用一個相應(yīng)的關(guān)鍵字,接下來是一個作為它的定義的代碼體,如下所示: 二者都...
    AdH閱讀 414評論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • 三年前開始健身,當(dāng)時因該只能稱為是鍛煉。每天幾組俯臥撐,仰臥起坐。開始時真的很難,我一直很瘦,耐力又差更別說力量訓(xùn)...
    marginalman閱讀 790評論 1 4
  • 上世紀(jì)二十年代末的一天,著名的金融投資家巴魯克到大街上的擦鞋點擦皮鞋,擦皮鞋的男孩雖然忙的不亦樂乎,但還是和周圍的...
    逐鹿客閱讀 491評論 2 1

友情鏈接更多精彩內(nèi)容