面向对象编程学习笔记

1.面向对象编程:

1.0 为何要有面向对象编程:

很早之前程序员就发现,随着软件的日趋复杂与庞大,维护往往变成了一个很棘手的问题.因为贯穿整个程序的依赖(dependencies),在一个程序中一个很小的改变就可能引起如同涟漪般扩散的偏差(errors).

而面向对象编程正是为了解决这个问题而诞生的.

1.1 何为面向对象编程:

面向对象编程(Object oriented programming)是一种基于对象的编程范型.在面向对象编程语言中,一切均是对象.

1.2 对象(object)的定义:

对象是指一个具体的事物.它有具体的行为(behaviors),有具体的属性(states).有时可以对应现实世界的事物,例如小狗聪聪,猫咪毛毛等.

1.3 类(class)的定义:

定义:

类相当于一副蓝图,定义了一类事物的抽象特点. 例如,"狗"这个类会包含狗的一切基础特征,即所有“狗”都共有的特征或行为,例如它的孕育、毛皮颜色和吠叫的能力。

作用:

这样创建一类具有相同行为与共通的属性的对象时,先创建一个这样的一个类,再用这个类去定义具体的对象,就可以少写很多代码.

1.4 面向对象编程的三大支柱:

  • 封装性(Encapsulation)

限定只有特定的类的对象才能调用特定类的方法,并且隐藏了方法的具体执行步骤.

示例:

/* 一个面向过程的程序会这样写: */
定义莱丝
莱丝.设置音调(5)
莱丝.吸气()
莱丝.吐气()

/* 而当狗的吠叫被封装到类中,任何人都可以简单地使用: */
定义莱丝是狗
莱丝.吠叫()
  • 继承(inheritance)

在某些情况下一个类会有子类,子类比父类更加具体.例如,“狗”这个类可能会有它的子类"牧羊犬"和"吉娃娃".子类会继承父类的属性和行为,并且包含它自己的.假设"狗"这个类有一个方法(行为)叫做“吠叫()”和一个属性叫做“毛皮颜色”。它的子类(前例中的牧羊犬和吉娃娃犬)会继承这些成员。

例如:

类牧羊犬:继承狗

定义莱丝是牧羊犬
莱丝.吠叫()    /* 注意这里调用的是狗这个类的吠叫方法。*/
  • 多态(Polymorphism)

多态(Polymorphism)是一个专业术语,意指"许多形态"("many shapes").更具体来说是同一种操作被用不同方式执行.

例如,狗和鸡都有“叫()”这一方法,但是调用狗的“叫()”,狗会吠叫;调用鸡的“叫()”,鸡则会啼叫。 我们将它体现在伪代码上:

类狗
开始
   公有成员:
       叫()
       开始
          吠叫()
       结束
结束

类鸡
开始
   公有成员:
       叫()
       开始
          啼叫()
       结束
结束

定义莱丝是狗
定义鲁斯特是鸡
莱丝.叫()
鲁斯特.叫()

这样同样做出叫这个动作,莱丝与鲁斯特的实际行为会大相径庭.

2. 关于对象(object)

2.1 initialize object:

语法:

Classname.new

示例:

  • 不带参数:
--- initialize class called GoodDog ---
class GoodDog 
    
end 

--- initialize object ----
sparky=GoodDog.new
  • 带参数:
--- 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 如何进行存取:

背景问题1:

如何输出@name的值

以上面代码为例,虽然有了instance variable,但是如果我们想要 输出 sparky 的name,那么应该怎么办?

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:

现在已经有了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")

现在运行下面的代码:

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

就会发现name的值改变了.

2.2.3.2 对上述代码进行重构:
  • 重构的原因:

Rubyist习惯使用相同的名称来命名instance variable的getter method 和setter method .

  • 重构后的代码:

统一使用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 对上述代码进行再次重构(attr_*):
  • 重构的原因:

上述代码占用的空间太多了,只有一个instance variable还好,若是有多个呢?例如height / weight.这样就太麻烦了.

  • 解决方案:

Ruby内置了一套方案来解决上述问题.

attr_accessor method 可以自动的帮助我们产生和上面一样的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内部使用getter / setter method:

2.2.4.1在class内部使用getter method 替换 instance variable:
  • 原因:

如果我们有一个social_security_numbers(用@ssn表示),我们并不想展示所有的数字,只想展示后四位,那么可以这样写:

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

如果我们需要多次使用到这行代码,与其多次重复写入,不如写一个method将这行代码封装起来.

另外原本的getter mehod 不能让别人直接调用,所以不如直接使用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内部使用setter method:
  • 原因:

如实在GoodDog class中有多个instance variable,而我们定义一个方法(change_info)用来同时改变着多变量的值:

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

为了与上面的在class内部使用getter method保持一致(consistence),从而使用setter_method来进行替换.

  • 失败的尝试:

根据上面的思路我们对change_info这个method进行了修改.

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

但是当我们进行检测时,却发现变量的值并没有改变.

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误以为我们是想创建新的变量,分别叫name/height/weight了.

    所以就会发现@name等变量并没有改变.

  • 使用self method进行修正:

    def change_info(n, h, w)        # using self method
      self.name = n
      self.height = h
      self.weight = w
    end
  • 为了保持一致,统一将调用getter method 的地方加上self.
def info
    "#{self.name} weighs #{self.weight} and is #{self.height} tall."
end
  • 最终结果是形成一个惯例(convention):
  • class 内,用到instance variable的地方使用getter method ;
  • class内,除setter method以外,需要改变instance variable值的地方统一使用setter method;
  • 在class内使用到getter / setter method 的地方都使用self method

3.关于类(class)

3.1 class variable:

3.1.1 作用:

不知道怎么描述,所以通过下面的代码进行感受.

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并没有什么关系.

3.3.1 为什么要有常量:

有时候我们无论如何都不想要定义的量的值改变,这时就使用常量.

3.3.2 常量的定义方法:
  • 语法:
  • 使用首字母大写的英语单词;
  • Rubyist习惯上将常量的所有字母都大写.
  • 示例:
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也没有什么关系.

3.4.1 自动调用to_s method的两种情况 :
  • puts method 自动调用to_method.

    示例:

    ---这里输出的结果是:前面是sparky这个对象对应的class(GoodDog),紧跟的一串数字/字母是这个是这个对象的ID编码---
    
    puts sparky      # => #<GoodDog:0x007fe542323320>
    

    puts sparky 等价于puts sparky.to_s

  • 字符串插值(string interpolation)自动调用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.
    

    在这里字符串插值自动的调用to_s method,然后将arr 和 x 两个变量转换成了对应的值,然后与字符串结合在了一起.

3.4.2 了解to_s method的自动调用的益处:

虽然当前感觉了解to_s method是无关紧要的,但这却会在日后帮助我们更好的读写oo code.

3.5 进一步了解self method

上面有两处使用了self method:

  • 告诉Ruby我们想要调用的是setter method,而不是创建新的变量;
  • 使用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">

通过上述代码我们可以发现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 继承的作用:

通过继承能够实现代码复用,从而达到以下好处:

  • 除去写重复代码的麻烦;
  • 方便debug.

4.1 继承的两种方式:

  • class inheritance
  • mixing in module

4.2 class inheritance:

4.2.1 语法:

使用 <符号去标记继承方向.

示例:

class Animal
  def speak
    "Hello!" 
  end
end

class GoodDog < Animal          # 标记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

当subclass中有与superclass中想相同的method时,subclass的object调用的就是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中调用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调用super的三种状况:
  1. 不含参数:
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. 含参数,但是不指定:
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的时候调用了Animal中的initialze method,从而导致bruno多了一个属性--name ---

bruno = GoodDog.new("brown")        # => #<GoodDog:0x007fb40b1e6718,@color="brown", @name="brown">
  1. 指定参数:
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,这个时候显然不能将对应的method提取出来放到Mammal或者是Animal中(因为Cat不可以swim).解决方案就是使用Mixing in module .

4.4.2 mixing in module的思路

就是将两个或者多个无法通过继承来dry up 的code 封装到一个容器中,然后让这些class调用这个容器中的内容.

具体来说是这样.将Fish与Dog都有的behavior(swim)用Swimmable这个module进行封装,然后让Fish与Dog进行调用.

4.4.3 mixing in module 的定义:

示例:

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

解释:

  • 使用首字母大写的单词;
  • rubyist 习惯上将单词以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在调用方法(method)时,是按照一定顺序进行的,这个顺序就叫method loopup path.

5.1.2 知道method lookup path的作用:

当我们研究一个较大的项目时,可能会困惑于那些方法是哪来的.但是若是知道了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

结果:

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

5.1.4 method lookup path:

顺序:

  • 在初始化对象的类中查找
  • 在该对象的module中查找(按照mixing进的module的顺序,进行倒序查找)
  • 在该类的父类中查找

示例:

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

输出结果:

---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归类放在一起;
  • 区分具有相同名字的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

调用方法:

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

5.3 私有/公共/?;し椒?private/public/protected):

5.3.1 私有方法(private method)

作用:

有时候我们只想让某个方法在class内部发生作用,而不再外部被调用,这个时候就使用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中被调用,且是直接调用不能用self method.

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

5.3.2 ?;し椒?protected method)

作用:

有时候我们想要在instance method中使用self.privatemethod或者objectname.privatemethod,的形式,但是有不想外界调用,这是就使用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 偶发的方法重写(accidental method overrding)

5.4.1 产生原因:

因为所有自己创建的类都继承自class Object,这就导致当有些method与Object中的method同名时,发生method overring.

示例:

例如:Object的send method可以调用某个方法,但是若被重写了,就会出问题.

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,避免发生重写(overrding),否则会对应用造成灾难性的后果.

参考资料:

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,698评论 0 9
  • 13.1类 类声明与函数声明很相似,头一行用一个相应的关键字,接下来是一个作为它的定义的代码体,如下所示: 二者都...
    AdH阅读 377评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 三年前开始健身,当时因该只能称为是锻炼。每天几组俯卧撑,仰卧起坐??际闭娴暮苣?,我一直很瘦,耐力又差更别说力量训...
    marginalman阅读 733评论 1 4
  • 上世纪二十年代末的一天,著名的金融投资家巴鲁克到大街上的擦鞋点擦皮鞋,擦皮鞋的男孩虽然忙的不亦乐乎,但还是和周围的...
    逐鹿客阅读 461评论 2 1