面向对象面试题

面向对象(Object-Oriented Programming, OOP)

特征

  • 封装
  • 继承
  • 多态

面向对象设计五大原则

单一职责原则(Single Pesponsibility Principle, SRP)

  • 一个类只需要做好一件事情

接口隔离原则(Interface Segregation Principle,ISP)

  • 一个类对另外一个类的依赖性应当是建立在最小接口上的

开放-封闭原则(Open-Close Principle, OCP)

  • 一个类是可以扩展的,而不可修改的

替换原则(Liskov Substitution Principle, LSP)

  • 替换原则也称里氏替换原则
  • 子类型必须能够替换掉它们的父类型,并出现在父类能够出现的任何地方
  • 父类的方法都要在子类中实现或重写,并且派生类只实现其抽象类中声明的方法,而不应当给出多余的方法定义或实现

依赖倒置原则(Dependence Inversion Principle, DIP)

  • 一个类不应该强依赖于另外一个类,每个类对于另外一个类都是可以替换的

PHP常用设计模式

工厂模式

工厂方法或者类生成对象,而不是在代码中直接new

应用场景:

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

Factory::createDatabase();

class Factory{
  static function createDatabase(){
    $db = new Database();
    return $db;
  }
}

单例模式

使某个类的对象仅允许创建一次

应用场景:

程序应用中,涉及到数据库操作时,如果每次操作的时候连接数据库,会带来大量的资源消耗。可以通过单例模式,创建唯一的数据库连接对象。

$db = Database::getInstance();
class Database{
  protected $db; 
  private function __construct(){
    	
  }
  
  static function getInstance(){
    if(!self::$db){
       self::$db = new self();
    }
    return self::$db;
  }
}

工厂模式+单例模式

//工厂模式
Factory::createDatabase();
class Factory{
  static function createDatabase(){
    //单例模式
    $db = Database::getInstance();
    return $db;
  }
}

class Database{
  protected $db; 
  private function __construct(){
    	
  }
  static function getInstance(){
    if(self::$db){
      return self::$db;
    }else{
       self::$db = new self();
       return self::$db;
    }
  }
}

注册模式

解决全局共享和交换条件

将类的对象注册到全局类上,在需要使用的时候可以直接访问

//定义一个空对象,模拟实例
$single = (object)[];
//将实例$single注册到数组中
Register::set("single", $single);
//获取该实例
$obj = Register::get("single");
class Register{
  protected static $objects;
  
  static function set($alias, $object){
    self::$objects[$alias] = $objects;
  }
  
  static function get($name){
    return self::$objects[$alias];
  }
  
  function _unset($alias){
    unset(self::$objects[$alias]);
  }
}

适配器模式

将各种截然不同的函数接口封装成统一的API

应用场景:

PHP中的数据库操作有MySQL,MySQLi,PDO三种,可以用适配器模式统一成一致,使不同的数据库操作,统一成一样的API

//声明接口,约定了统一api的方式,适配器都有哪些行为
//分别创建每个适配器的实例,必须继承至这个接口,必须实现这些接口所约定的所有方法

$db = new Mysql();
$db->connect('127.0.0.1', 'root', 'root', 'test');
$db->query('show databases');
$db->close();
interface IDatabase{
  function connect($host, $user, $password, $dbname);
  function query($sql);
  function close();
}
class Mysql implements IDatabase{
  protected $connect;
   function connect($host, $user, $password, $dbname){
     $connect = mysql_connect($host, $user, $password);
     mysql_select_db($dbname, $connect);
     $this->connect = $connect;
   }
  function query($sql){
    $res = mysql_query($sql, $this->connect);
    return $res
   }
  function close(){
    mysql_close($this->connect);
   }
}

class Mysqli implements IDatabase{
  protected $connect;
   function connect($host, $user, $password, $dbname){
     $connect = mysqli_connect($host, $user, $password, $connect);
     $this->connect = $connect;
   }
  function query($sql){
    $res = mysqli_query($this->connect, $sql);
    return $res
   }
  function close(){
    mysqli_close($this->connect);
   }
}

class Pdo implements IDatabase{
  protected $connect;
  function connect($host, $user, $password, $dbname){
     $connect = new \PDO("mysql:host=$host;dbname=$dbname", $user, $password);
     $this->connect = $connect;
  }
  function query($sql){
    return $this->connect->query($sql);
   }
  function close(){
    unset($this->connect);
  }
}

策略模式

将一组特定的行为和算法封装成类,以适应某些特定的上下文环境

应用场景:

假如一个电商网站系统,针对男女用户要各自跳转到不同的商品类目,并且所有的广告位展示不同的广告

class Page{
  protected $UserStrategy;
  function index(){
    $this->UserStrategy->showCategory();
  }
  function setStrategy(UserStrategy $UserStrategy){
    $this->UserStrategy = $UserStrategy;
  }
}

$page = new Page()if(isset($_GET['female'])){
  $UserStrategy = new FemaleUserStrategy();
}else{
  $UserStrategy = new MaleUserStrategy();
}
$page->setStrategy($UserStrategy)
$page->index();

//两种策略 一种针对男性,一种针对女性
class MaleUserStrategy implements UserStrategy{
  function showAd(){
    echo '男装服饰';
  }
  function showCategory(){
     echo '男装';
  }
}

class FemaleUserStrategy implements UserStrategy{
  function showAd(){
    echo '女装服饰';
  }
  function showCategory(){
     echo '女装';
  }
}
interface  UserStrategy{
  function showAd();
  function showCategory();
}

数据对象映射模式

将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作

应用场景:

实现一个ORM类,将复杂的sql语句映射成对象属性的操作,结合使用数据对象映射模式、工厂模式、注册模式

class User{
  public $id;
  public $name;
  public $mobile;
  public $regtime;
  
  protected $db;
  function __construct($id){
    $this->db = new Mysqli();
    $this->db->connect('127.0.0.1', 'root', 'root', 'test');
    $res = $this->db->query('select * from user limit');
    $data = $res->fetch_assoc();
    $this->id = $data['id'];
    $this->name= $data['name'];
    $this->mobile = $data['mobile'];
    $this->regtime = $data['regtime'];
  }
  
  function __destruct(){
    $this->db->query("update user set name = '{$this->name}' where id = '{$this->id}'");
  }
  
}

$user = new User(1);
$user->mobile = '17859902536';
$user->name = 'username'
$user->regtime = time();

观察者模式

观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新。

应用场景:一个事件发生后,要执行一连串的更新。传统的编程方式就是在事件的代码之后直接加入处理逻辑。当更新的逻辑增加之后,代码会变得难以维护,这种方法是耦合的,侵入式的,增加新的逻辑需要修改事件主体的代码。观察者模式实现了低耦合,非侵入式的通知与更新机制。

php链式操作的实现,调用的每个方法:return $this;

$Event = new Event();
$Event->addObserver(new Observer1);
$Event->addObserver(new Observer2);
$Event->trigger();

class Event extends EventGenerator{
  function trigger(){
    echo "Event";
    $this->notify();
  }
}
//抽象类
abstract class EventGenerator{
  private $Observers = array();
  function addObserver(Observer $Observer){
    $this->Observers[] = $Observer;
  }
  function notify(){
    foreach($this->Observers as $Observer){
      $Observer->update();
    }
  }
}

class Observer1 implements Observer{
  function update($event_info = null){
    echo '逻辑1';
  }
}

class Observer2 implements Observer{
  function update($event_info = null){
    echo '逻辑2';
  }
}

interface Observer{
  function update($event_info = null);
}

原型模式

与工厂模式作用类似,都是用来创建对象

与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样就免去了类创建时重复的初始化操作

原型模式适用于大对象的创建,创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可

$prototype = new Canvas();
$prototype->init();
//原型模式
$Canvas1 = clone $prototype;

$Canvas2 = clone $prototype;

装饰器模式

可以动态的添加修改类的功能

一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法

使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性

$canvas1 = new Canvas();
$canvas1->init();
$canvas1->addDecorator(new ColorDrawDecorator('green'));
$canvas1->addDecorator(new SizeDrawDecorator('16'));
$canvas1->draw();

interface DrawDecorator{
  function beforeDraw();
  function afterDraw();
}

class SizeDrawDecorator implements DrawDecorator{
   protected $size;
   function __construct($size = '14'){
     $this->size = $size;
   }
   function beforeDraw(){
     //todo
   }
   function afterDraw(){
      //todo
   }
}

class ColorDrawDecorator implements DrawDecorator{
   protected $color;
   function __construct($color = 'red'){
     $this->color = $color;
   }
   function beforeDraw(){
      //todo
   }
   function afterDraw(){
      //todo
   }
}

class Canvas{
  protected $DrawDecorators = array();
  function addDecorator(DrawDecorator $DrawDecorator){
    $this->DrawDecorators[] = $DrawDecorator;
  }
  
   function beforeDraw(){
    foreach($this->DrawDecorators as $DrawDecorator){
        $DrawDecorator->beforeDraw();
    }
  }
  
    function afterDraw(){
      $DrawDecorators = array_reverse($this->DrawDecorators);
      foreach($DrawDecorators as $DrawDecorator){
        $DrawDecorator->afterDraw();
      }
   }
  
  function draw(){
    $this->beforeDraw();
    //todo 中间代码
    $this->afterDraw();
  }
}

迭代器模式

不需要了解内部实现的前提下,遍历一个聚合对象的内部元素

相对于传统的编程模式,迭代器模式可以隐藏遍历元素的所需的操作

代理模式

在客户端与实体之间建立一个代理对象,客户端对实体进行操作全部委派给代理对象,隐藏实体的具体的实现细节

代理还可以与业务代码分离,部署到另外的服务器,业务中通过RPC来委派任务(数据库主从分离)

$Proxy = new Proxy();
$Proxy->getUserName($id);
$Proxy->setUserName($id, $username);
class IUserProxy{
  function getUserName($id);
  function setUserName($id, $username);
}

class Proxy implements IUserProxy{
  function getUserName($id){
    $db = Factory::getDatabase('slave');
    $db->query();
  }
  function setUserName($id, $username){
    $db = Factory::getDatabase('master');
    $db->update();
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值