面向过程与面向对象思维的比较

实习第五天CTO给我们分享了一个TDD的面试题目的答案,让我们评价一下。在大家挑毛病的时候,我发现自己有很多以前从没注意过的地方,比方PSR规范,命名规则等等。
题目:https://github.com/joelpittet/phpinterview
答案:https://github.com/tsuijie/phpinterview
今天自己在尝试解答这道题目时发现,有两个测试怎么也通过不了。搞了很长时间,还是不行,只好借鉴一下答案+_+,不过我发现答案和我完全就是两种看待问题的思路,一个是面向过程,另一个则是面向对象去思考。而且我认为两种做法都能解释的通。

题目

题目是一个电影院售票,如何让票价最便宜的问题,讲道理放在高中就是一道稍微麻烦点的应用题,只不过现在扯上了编程。

  • 售票规则:
Basic admission rates (regular weekday, 2D movie, <=120 min, parquet):
General admission                               $11.00
Students                                        $8.00
Senior Citizens (65 & older)                    $6.00
Children (under 13)                             $5.50
Group (20 people or more)                       $6.00 each
Exceptions:
3D movie                                        +$3.00
Over-length (more than 120 min.)                +$1.50
Movie Day (Thurdsday, except for groups!)       -$2.00
Weekends                                        +$1.50
Loge                                            +$2.00
  • 测试文件:
<?php
namespace Kata\Tests;
use Kata\DaysOfWeek;
use Kata\Movie;
class MovieTest extends \PHPUnit_Framework_TestCase {
  /**
   * Data provider for movies.
   *
   * @return array
   */
  public function movieProvider() {
    return [
      [[72, DaysOfWeek::TUE, TRUE, FALSE], 44.0, "2D, parquet, Tuesday"],
      [[72, DaysOfWeek::TUE, TRUE, TRUE], 56.0, "3D, parquet, Tuesday"],
      [[72, DaysOfWeek::TUE, FALSE, TRUE], 64.0, "3D, loge, Tuesday"],
      [[120, DaysOfWeek::THU, FALSE, TRUE], 56.0, "3D, loge, movie day"],
      [[72, DaysOfWeek::SAT, FALSE, TRUE], 70.0, "3D, loge, Saturday"],
      [[72, DaysOfWeek::SUN, FALSE, TRUE], 70.0, "3D, loge, Sunday"],
      [[145, DaysOfWeek::WED, TRUE, FALSE], 50.0, "overlength, 2D, parquet, Wednesday"],
    ];
  }
  /**
   * Tests middle age non student buyers.
   *
   * @dataProvider movieProvider
   */
  public function testMiddleAgeNonStudents($movie, $expectedResult, $message) {
    $tickets = [[35, FALSE], [35, FALSE], [35, FALSE], [35, FALSE]];
    $movie[] = $tickets;
    $result = call_user_func_array([$this, 'calc'], $movie);
    $this->assertEquals($expectedResult, $result, $message . ", mid-age, no student");
  }
  protected function applyTickets(Movie $cashReg, $runtime, $day, $isParquet, $is3D, $tickets) {
    $cashReg->startPurchase($runtime, $day, $isParquet, $is3D);
    foreach ($tickets as $ticket) {
      $cashReg->addTicket($ticket[0], $ticket[1]);
    }
    return $cashReg;
  }
  /**
   * Calculate helper.
   *
   * @param int $runtime
   *   The runtime in minutes.
   * @param int $day
   *   The day of the week in integer value.
   * @param bool $isParquet
   *   If the movie is Parquet or Lode.
   * @param bool $is3D
   *   Whether the movie is in 3D or 2D.
   * @param array $tickets
   *   A list of tickets.
   *
   * @return float
   */
  protected function calc($runtime, $day, $isParquet, $is3D, $tickets) {
    $cashReg = new Movie();
    $this->applyTickets($cashReg, $runtime, $day, $isParquet, $is3D, $tickets);
    return $cashReg->finishPurchase();
  }
  public function testNoTicketsCostsZero() {
    $result = $this->calc(0, DaysOfWeek::MON, FALSE, FALSE, []);
    $this->assertNotNull($result, "No tickets costs are not NULL");
    $this->assertNotInternalType('string', $result, "No tickets costs are not a string");
    $this->assertEquals(0, $result, "No tickets costs zero");
  }
  public function testOverlength2DParquetWednesdayMidAgeStudents() {
    $tickets = [[35, FALSE], [35, FALSE], [64, TRUE], [35, TRUE]];
    $result = $this->calc(121, DaysOfWeek::WED, TRUE, FALSE, $tickets);
    $this->assertEquals(44.0, $result, "overlength, 2D, parquet, wednesday, mid-age, students");
  }
  public function testOverlength2DParquetMondaySeniorNoStudents() {
    $tickets = [[35, FALSE], [35, FALSE], [64, FALSE], [65, FALSE]];
    $result = $this->calc(123, DaysOfWeek::MON, TRUE, FALSE, $tickets);
    $this->assertEquals(45.0, $result, "overlength, 2D, parquet, monday, senior, no students");
  }
  public function testOverlength2DParquetTuesdaySeniorStudents() {
    $tickets = [[35, FALSE], [35, FALSE], [64, FALSE], [68, TRUE]];
    $result = $this->calc(145, DaysOfWeek::TUE, TRUE, FALSE, $tickets);
    $this->assertEquals(45.0, $result, "overlength, 2D, parquet, tuesday, senior students");
  }
  public function testOverlength2DParquetTuesday1ChildNoStudents() {
    $tickets = [[35, FALSE], [35, FALSE], [64, FALSE], [10, FALSE]];
    $result = $this->calc(145, DaysOfWeek::TUE, TRUE, FALSE, $tickets);
    $this->assertEquals(44.5, $result, "overlength, 2D, parquet, tuesday, 1 child, no students");
  }
  public function test2DparquetTuesdayGroupNoStudents() {
    $tickets = [];
    for ($i = 0; $i < 23; $i++) {
      $tickets[] = [35, FALSE];
    }
    $result = $this->calc(72, DaysOfWeek::TUE, TRUE, FALSE, $tickets);
    $this->assertEquals(138.0, $result, "2D, parquet, tuesday, group, no students");
  }
  public function test3DParquetTuesdayGroupNoStudents() {
    $tickets = [];
    for ($i = 0; $i < 23; $i++) {
      $tickets[] = [35, FALSE];
    }
    $result = $this->calc(72, DaysOfWeek::TUE, TRUE, TRUE, $tickets);
    $this->assertEquals(207.0, $result, "3D, parquet, tuesday, group, no students");
  }
  public function test2DGroupOfKidsWithTwoAdults() {
    $tickets = [];
    for ($i = 0; $i < 24; $i++) {
      $tickets[] = [12, FALSE];
    }
    $tickets[] = [45, FALSE];
    $tickets[] = [27, FALSE];
    $result = $this->calc(72, DaysOfWeek::FRI, TRUE, FALSE, $tickets);
    $this->assertEquals(144.0, $result, "2D, group of kids with two adults");
  }
  public function test2D17KidsWithTwoAdults() {
    $tickets = [];
    for ($i = 0; $i < 17; $i++) {
      $tickets[] = [12, FALSE];
    }
    $tickets[] = [45, FALSE];
    $tickets[] = [27, FALSE];
    $result = $this->calc(72, DaysOfWeek::WED, TRUE, FALSE, $tickets);
    $this->assertEquals(115.5, $result, "2D, 17 kids with two adults");
  }
  public function testOverlengthLoge3DMovieDayGroup() {
    $tickets = [];
    for ($i = 0; $i < 5; $i++) {
      $tickets[] = [12, FALSE];
    }
    for ($i = 0; $i < 7; $i++) {
      $tickets[] = [45, FALSE];
    }
    for ($i = 0; $i < 4; $i++) {
      $tickets[] = [75, FALSE];
    }
    for ($i = 0; $i < 8; $i++) {
      $tickets[] = [27, TRUE];
    }
    $result = $this->calc(125, DaysOfWeek::THU, FALSE, TRUE, $tickets);
    $this->assertEquals(297.5, $result, "overlength, loge, 3D, movie-day group");
  }
  public function testOverlengthLoge3DmovieDayNonGroup() {
    $tickets = [];
    for ($i = 0; $i < 2; $i++) {
      $tickets[] = [12, FALSE];
    }
    for ($i = 0; $i < 7; $i++) {
      $tickets[] = [45, FALSE];
    }
    for ($i = 0; $i < 4; $i++) {
      $tickets[] = [75, FALSE];
    }
    for ($i = 0; $i < 4; $i++) {
      $tickets[] = [27, TRUE];
    }
    $result = $this->calc(125, DaysOfWeek::THU, FALSE, TRUE, $tickets);
    $this->assertEquals(220.5, $result, "overlength, loge, 3D, movie-day non-group");
  }
  public function testMultipleTransactionSameRegister() {
    $cashReg = new Movie();
    $tickets = [
      [35, FALSE], [35, FALSE], [35, FALSE], [35, FALSE], [35, FALSE],
    ];
    $this->applyTickets($cashReg, 90, DaysOfWeek::MON, TRUE, TRUE, $tickets);
    $this->assertEquals(70.0, $cashReg->finishPurchase(), "multiple transactions, same register");
    $this->applyTickets($cashReg, 90, DaysOfWeek::MON, TRUE, TRUE, $tickets);
    $this->assertEquals(70.0, $cashReg->finishPurchase(), "multiple transactions, same register");
  }
}

我的思路

售票单价中有5种基于年龄,是否是学生和是否团购来判断的价位,其中儿童票最便宜,普通票最贵。
那么就是购票人是一个对象,其中年龄,票价,是否是学生,是否团购是他的属性。
由于单次售票过程中附加条件都是一样的,所以属于对象的公共变量。只有当团购而且是电影日时不同。

  • 那么在Movie类中就的startPurchase()方法就可以用来初始化和附加条件判断。addTicket()方法用来统计人数与当前的总票价。finishPurchase()方法用来最后的票价检查,检测是否有更便宜的购票方式。
  • 由于儿童票最便宜,团购票次之,所以肯定是儿童票越多越好,而且由于年龄是固有属性所以儿童要被独立出来。当人数大于20时,就有了团购的可能性,但当有儿童存在时团购票价不一定就比较低,所以要在最后进行判断到底组不组团。
  • 我的代码:
<?php
namespace Kata;
/**
 * Class Movie.
 */
class Movie {
    const CHILDREN = 5.5;
    const SENIOR_CITIZENS = 6.0;
    const STUDENTS = 8.0;
    const GENERAL_ADMISSION = 11.0;
    const GROUP = 6.0;
    const IS_3D_MOVIE = 3.0;
    const OverLength = 1.5;
    const MOVIE_DAY = -2.0;
    const WEEKENDS = 1.5;
    const LOGE = 2.0;
    protected $TotalPrice = 0;
    protected $GroupNum = 0;
    protected $TotalNum = 0;
    protected $Exceptions = 0;
    protected $IsMovieDay = false;
  /**
   * Begins a transaction.
   *
   * @param int $runtime
   *   The minutes of the user.
   * @param int $day
   *   The integer value from DaysOfWeek constants.
   * @param bool $isParquet
   *   Is either parquet or lode.
   * @param bool $is3D
   *   Is the film in 3D or 2D.
   */
  public function startPurchase($runtime, $day, $isParquet, $is3D) {
      $this->TotalPrice = 0;
      $this->GroupNum = 0;
      $this->TotalNum = 0;
      $this->Exceptions = 0;
      $this->IsMovieDay = false;
      if ($runtime > 120){
          $this->Exceptions += self::OverLength;
      }
      if ($day == DaysOfWeek::THU){
          $this->Exceptions += self::MOVIE_DAY;
          $this->IsMovieDay = true;
      } elseif ($day == DaysOfWeek::SUN || $day == DaysOfWeek::SAT){
          $this->Exceptions += self::WEEKENDS;
      }
      if (! $isParquet){
          $this->Exceptions += self::LOGE;
      }
      if ($is3D){
          $this->Exceptions += self::IS_3D_MOVIE;
      }
  }

  /**
   * Adds a ticket to the transaction.
   *
   * @param int $age
   *   The age of the ticket holder.
   * @param bool $isStudent
   *   Whether the ticket is for a student.
   */
  public function addTicket($age, $isStudent) {
      $this->TotalNum ++;
      if ($age < 13){
          $this->TotalPrice += self::CHILDREN;
      } elseif ($age >= 65){
          $this->TotalPrice += self::SENIOR_CITIZENS;
          $this->GroupNum ++;
      } elseif ($isStudent){
          $this->TotalPrice += self::STUDENTS;
          $this->GroupNum++;
      } else {
          $this->TotalPrice += self::GENERAL_ADMISSION;
          $this->GroupNum ++;
      }
  }

  /**
   * Get the final price.
   *
   * @return float
   *   The total price of the transaction.
   */
  public function finishPurchase() {
      if ($this->TotalNum > 20){
          if ($this->GroupNum >= 20){
              if ($this->IsMovieDay){
                  $this->TotalPrice = $this->GroupNum * (self::GROUP - self::MOVIE_DAY) + ($this->TotalNum - $this->GroupNum) * self::CHILDREN;
              } else {
                  $this->TotalPrice = $this->GroupNum * self::GROUP + ($this->TotalNum - $this->GroupNum) * self::CHILDREN;
              }
          } else {
              if ($this->IsMovieDay){
                  $OtherPrice = $this->GroupNum * (self::GROUP - self::MOVIE_DAY) + ($this->TotalNum - $this->GroupNum - 20 + $this->GroupNum) * self::CHILDREN;
              } else {
                  $OtherPrice = 20 * self::GROUP + ($this->TotalNum - $this->GroupNum - 20 + $this->GroupNum) * self::CHILDREN;
              }
              $this->TotalPrice = ($OtherPrice < $this->TotalPrice) ? $OtherPrice : $this->TotalPrice;
          }
      }
//      echo 'xxxxxxxx'.($this->TotalNum - $this->GroupNum - 20 + $this->GroupNum).'xxxxx';
//      echo 'ppppppGroupNum'.$this->GroupNum.'???????TotalNum'.$this->TotalNum.'----------TotalPrice'.$this->TotalPrice.'-----------Exceptions'.$this->Exceptions.'*********\n';
      $this->TotalPrice += ($this->TotalNum * $this->Exceptions);
      return $this->TotalPrice;
  }
}

虽然思路上是面向对象,但实际上在写的时候我并没有完全按照规范去写,因为这毕竟只是一个小题目。
而且我在最后的判断中依旧是有问题的,因为会有一个更复杂的比较方式,由于存在组团时就不能享受电影日的优惠这个条件,所以如果有一定量的儿童或老人时就会出现到底多少人组团表较合适,那这基本就是一个多元方程了,有种做奥数题的感觉=_=。(当然也可能是我想复杂了。。。)

  • 在最开始进行测试时我忽略了附加条件中电影日的条件,所以在最后的finishPurchase()中又修改了一些代码,才通过了测试。
  • 在测试文件的最后一个单元测试中我发现测试时要满足多次售票但不能重新新建对象,所以就在startPurchase() 中强制初始化了部分参数。
  • 不幸的是最后我依旧没能通过其中两个测试,分别是:
 public function test2DGroupOfKidsWithTwoAdults() {
    $tickets = [];
    for ($i = 0; $i < 24; $i++) {
      $tickets[] = [12, FALSE];
    }
    $tickets[] = [45, FALSE];
    $tickets[] = [27, FALSE];
    $result = $this->calc(72, DaysOfWeek::FRI, TRUE, FALSE, $tickets);
    $this->assertEquals(144.0, $result, "2D, group of kids with two adults");
  }
public function testOverlengthLoge3DMovieDayGroup() {
    $tickets = [];
    for ($i = 0; $i < 5; $i++) {
      $tickets[] = [12, FALSE];
    }
    for ($i = 0; $i < 7; $i++) {
      $tickets[] = [45, FALSE];
    }
    for ($i = 0; $i < 4; $i++) {
      $tickets[] = [75, FALSE];
    }
    for ($i = 0; $i < 8; $i++) {
      $tickets[] = [27, TRUE];
    }
    $result = $this->calc(125, DaysOfWeek::THU, FALSE, TRUE, $tickets);
    $this->assertEquals(297.5, $result, "overlength, loge, 3D, movie-day group");
  }
  • 从第一个测试函数来看是24个儿童与两个成年人,没有任何附加的票价。那么这就是一个需要比较两种算法的测试了。
    =>第一种:不组团。245.5+211=154
    =>第二种:组团。206+65.5=153
    那么第二种方法便宜了1元。但测试中却显示最低票价可以为144元。这就难办了,到底怎么才能达到144的票价呢?难不成是儿童与成人都买团购票?很明显这不是最佳选项。
  • 而第二测试函数是5个儿童,7个普通人,4个老人,8个学生,附加条件基本都有了而且是电影日存在优惠。那这个就属于我没完善的部分了,因为不组团肯定是最贵的要300.5。而如果组团就存在三类人了,普通团员单价12.5,单独老人单价11.5,单独儿童单价10。那团员至少有15人,而剩下的5人要在老人与儿童中挑选,所以最佳比例还需要再做计算,但由于老人比较贵所以老人都要入团,而儿童也要有一个入团才能团购。所以最后票价为290。这比测试文件中的答案297.5少。

答案的思路

下面是通过所有测试的答案:

<?php
namespace Kata;
/**
 * Class Movie.
 */
class Movie {
    private $runtime;
    private $day;
    private $isParquet;
    private $is3D;
    private $isGroup;
    private $queue = array();
    private $fee3D = 3.00;
    private $feeOverLength = 1.50;
    private $feeMovieDay = -2.00;
    private $feeWeekends = 1.50;
    private $feeLoge = 2.00;
    private $rateChildren = 5.50;
    private $rateSenior = 6.00;
    private $rateGroup = 6.00;
    private $rateStudents = 8.00;
    private $rateNormal = 11.00;
  /**
   * Begins a transaction.
   *
   * @param int $runtime
   *   The minutes of the user.
   * @param int $day
   *   The integer value from DaysOfWeek constants.
   * @param bool $isParquet
   *   Is either parquet or lode.
   * @param bool $is3D
   *   Is the film in 3D or 2D.
   */
  public function startPurchase($runtime, $day, $isParquet, $is3D) {
      $this->runtime = $runtime;
      $this->day = $day;
      $this->isParquet = $isParquet;
      $this->is3D = $is3D;
  }
  /**
   * Adds a ticket to the transaction.
   *
   * @param int $age
   *   The age of the ticket holder.
   * @param bool $isStudent
   *   Whether the ticket is for a student.
   */
  public function addTicket($age, $isStudent) {
      $this->queue[] = ['age' => $age, 'isStudent' => $isStudent];
  }
  /**
   * Get the final price.
   *
   * @return float
   *   The total price of the transaction.
   */
  public function finishPurchase() {
      $price = 0;
      $count = count($this->queue);
      $this->isGroup = $count >= 20 ? true : false;
      foreach ($this->queue as $ticket) {
          if ($ticket['age'] < 13) {
              $price += $this->rateChildren;
          } elseif ($ticket['age'] >= 65) {
              $price += $this->rateSenior;
          } elseif ($this->isGroup) {
              $price += $this->rateGroup;
          } elseif ($ticket['isStudent']) {
              $price += $this->rateStudents;
          } else {
              $price += $this->rateNormal;
          }
      }
      if ($this->is3D) {
          $price += $count * $this->fee3D;
      }
      if (!$this->isParquet) {
          $price += $count * $this->feeLoge;
      }
      if ($this->runtime > 120) {
          $price += $count * $this->feeOverLength;
      }
      if ($this->day === 4 && !$this->isGroup) {
          $price += $count * $this->feeMovieDay;
      }
      if (in_array($this->day, array(0, 6)))
          $price += $count * $this->feeWeekends;
      // clean register queue after purchase
      $this->queue = [];
      return $price;
  }
}

答案中startPurchase()用来给附加项初始化赋值。addTicket()用来给所有的票这个大数组赋值。finishPurchase()则是具体的处理逻辑与清空大数组。

  • 从finishPurchase()中可以看出,他是计数然后判断是不是达到组团要求,再进行年龄的判断并统计目前的票价,最后再进行各种附加项的判断与赋值。这是明显的面向过程的编程思路,一步步的进行逻辑判断与赋值。
  • 但是如果仔细看就会发现他在年龄与是否满足组团条件上与我有些不同。他是直接判断年龄然后再直接判断是否满足组团条件,而我则是判断完所有的年龄后,单独进行组团条件的判断。
  • 而且他的附加条件中电影日的判断也是一刀切的做法。
    这样就造成了票价的不同。按照他的做法我第一个没通过的单元测试的逻辑过程是这样的。先来的24个儿童全部都是5.5,后来的两个成人则是6,结果票价为5.524+26=144和测试文件中一样。同样第二个单元测试则是55.5+196+24*(3+2+1.5)=297.5。

最后

所以从两种思路上来看都没有什么问题,我感觉OOP注重思考问题的本质,而面向过程则注重解决问题的逻辑。
虽然答案通过了测试,但个人感觉这样或许并不合理。而且如果以后是基于单元测试进行编程,那么单元测试部分必须完全正确,不然产生了歧义的话就会造成编码的反复修改,丧失了敏捷开发的本意。不过,讲道理一般TDD都是自己负责写单元测试的代码,应该不太会产生歧义。。。。。。

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

推荐阅读更多精彩内容

  • 不支持上传文件,所以就复制过来了。作者信息什么的都没删。对前端基本属于一窍不通,所以没有任何修改,反正用着没问题就...
    全栈在路上阅读 1,926评论 0 2
  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,017评论 1 10
  • 我的心上人应该是个运动健将。 为什么突然有这种想法? 因为在这个春风沉醉的夜晚,作为懒癌晚期患者的的我,终于迈开腿...
    月光海儿阅读 300评论 0 2
  • 这个女人,同以前简直判若两人。或许以前,我是为了生存,为了自己那自卑的虚荣心,也为了自己青春期的一些生理需求,算是...
    晏大仙阅读 178评论 0 0
  • 谁没有一段不堪回首的过去,为何你却要揪着不放 --01-- 在大都市待了5、6年,黄倩倩突然感觉心有点累了,有点厌...
    晓风清泉一壶酒阅读 266评论 0 1