分类 灵魂思想 下的文章

状态模式是根据状态来执行不同的功能,通常以switch和if-ifelse来逻辑判断。面向对象设计,它的目的就是希望代码能够根据责任、功能来进行分解,不再是一大长串。状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的时候,把状态的判断转移到表示不同状态的一系列类当中,把复杂的判断逻辑简化。
状态模式:当一个对象内在的状态改变时允许改变他的行为,这个对象看起来像是改变了其类。
当一个对象运行时,该执行什么方法,是取决于它的状态的时候,我们不用臃肿的条件判断语句,而是使用状态模式。
场景:人的行为,早上吃早饭,然后走路,上班,吃午饭,上班,走路,回家吃晚饭,睡觉。用条件控制来实现,if(time()==8点){ 吃早饭 }else if()....看看GoF的状态模式如何实现人的行为。以PHP为代码环境。

<?php
class Person{
    private $state;
    private $time;
    public function __construct(){
        $this->state = new Breakfast();
    }
    public function getTime(){
        return $this->time;
    }
    public function setTime($time){
        $this->time = $time;
    }
    public function getState(){
        return $this->state;
    }
    public function setState($state){
        $this->state = $state;
    }
    public function behavior(){
        $this->state->behavior($this);
    }
}
class Breakfast{
    public function behavior($personObj){
        if($personObj->getTime() < 8){
            echo '吃早餐<br>';
        }else{
            $personObj->setState(new Walk());
            $personObj->behavior();
        }
    }
}
class Walk{
    public function behavior($personObj){
        if($personObj->getTime() < 9 || ($personObj->getTime() > 18 && $personObj->getTime() < 19)){
            echo '走路<br>';
        }else{
            if($personObj->getTime() > 9 && $personObj->getTime() < 18){
                $personObj->setState(new Work());
                $personObj->behavior();
            }else{
                $personObj->setState(new Dinner());
                $personObj->behavior();
            }
        }
    }
}
class Work{
    public function behavior($personObj){
        if($personObj->getTime() < 12 || ($personObj->getTime() > 13 && $personObj->getTime() < 18)){
            echo '工作<br>';
        }else{
            if($personObj->getTime() < 13){
                $personObj->setState(new Lunch());
                $personObj->behavior();
            }else{
                $personObj->setState(new Walk());
                $personObj->behavior();
            }
        }
    }
}
class Lunch{
    public function behavior($personObj){
        if($personObj->getTime() < 13){
            echo '吃午餐<br>';
        }else{
            $personObj->setState(new work());
            $personObj->behavior();
        }
    }
}
class Dinner{
    public function behavior($personObj){
        if($personObj->getTime() < 20){
            echo '吃晚餐<br>';
        }else{
            $personObj->setState(new Sleep());
            $personObj->behavior();
        }
    }
}
class Sleep{
    public function behavior($personObj){
        echo '睡觉<br>';
        exit;
    }
}
//客户端/接口
$personObj = new Person();
//时间表
$timeList = array(7, 8.5, 10, 12.5, 15, 18.5, 19.5);
foreach($timeList as $time){
    $personObj->setTime($time);
    $personObj->behavior();
}

抽象工厂模式,是工厂方法模式的演变,而工厂方法模式,是简单工厂模式的进化。抛弃了应用的条件控制语句,无论是switch还是if-ifelse。是设计模式的一种。
抽线工厂模式来自于方法模式和简单工厂模式的进化与整合,其实,我已经要疯了,23种设计模式,现在已经出现了三种工厂模式。
抽象工厂模式:提供一个创建一系列相关的、相互依赖的对象接口,而无需指定他们的具体类。
对于面向过程的编程,以及套在class里的面向对象的编程,修改起来是大批量的,是非常丑陋的。我常常告诫自己,编程是一门艺术,每个程序员都是艺术家,写出优美的,有艺术感的代码,并且是高效的,低成本的,这就是编程之美!
场景:原本是mysql,现在要换成oracle。以PHP为代码环境。现在有两张表,一个是用户表user,一个是公司表company。

<?php
class Db{
    private static $dbName = 'mysql';
    public static function createUserDbObj(){
        $className = self::$dbName . 'UserDbModel';
        return new $className();
    }
    public static function createCompanyDbObj(){
        $className = self::$dbName . 'CompanyDbModel';
        return new $className();
    }
}
interface User{
    public function get();
    public function set();
}
class mysqlUserDbModel implements User{
    public function get(){
        echo '从Mysql中查找用户记录<br>';
    }
    public function set(){
        echo '从Mysql中添加用户记录<br>';
    }
}
class oracleUserDbModel implements User{
    public function get(){
        echo '从Oracle中查找用户记录<br>';
    }
    public function set(){
        echo '从Oracle中添加用户记录<br>';
    }
}
interface Company{
    public function get();
    public function set();
}
class mysqlCompanyDbModel implements User{
    public function get(){
        echo '从Mysql中查找公司记录<br>';
    }
    public function set(){
        echo '从Mysql中添加公司记录<br>';
    }
}
class oracleCompanyDbModel implements User{
    public function get(){
        echo '从Oracle中查找公司记录<br>';
    }
    public function set(){
        echo '从Oracle中添加公司记录<br>';
    }
}
//客户端/接口
$userDbObj = Db::createUserDbObj();
$companyDbObj = Db::createCompanyDbObj();
$userDbObj->get();
$userDbObj->set();
$companyDbObj->get();
$companyDbObj->set();

现在代码的方式,是把选择数据库给写死到程序中了(Db类), 我们可以以更加灵活的方式,比如:
1、配置

config.php
<?php
define('DB_NAME', 'mysql');

2、文件

$f = fopen('config', 'r');
$config = '';
while(!feof($f)){
    $config .= fgets($f);
    $config .= ' ';
}
//----------------我是分割线-----------
$config = file_get_contents('config');
//-------------------------------------------
//$config = 'dbtype:mysql|username:root|password:root';
$config = explode('|', $config);
foreach($config as $k=>$c){
    $data = explode(':', $c);
    unset($config[$k]);
    $config[$data[0]] = $data[1];
}
print_r($config);

个人认为:这种方式的数据库应用代码设计,仍旧是很繁琐的,每增加一张表,需要增加各个类型的数据库类各一个。所以,本例仅仅是为了演示说明抽象工厂模式。

观察者模式,又叫做订阅-发布模式。当一个对象的改变需要同时改变多个对象的时候,可以使用法不这模式。设计模式中的观察者模式,就是为了解除类之间的耦合,使双方都依赖于抽象而不是依赖于具体。在实际生活中,比如我们更换了手机号,需要通知大家的时候,我们就是主题,或者通知者,而需要通知的人就是观察者列表,一条短信的群发告诉大家,就是观察者模式的应用。

<?php
//主题者、通知者抽象类。
abstract class Subject{
	private $observerList = array();
	public function add(&$obj, $action){
		$this->observerList[] = array('obj'=>$obj, 'action'=>$action);
	}
	public function notice(){
		foreach($this->observerList as $observer){
			$obj = $observer['obj'];
			$action = $observer['action'];
			$obj->$action;
		}
	}
}
//具体的通知者
class I extends Subject{
	private $status;
	public function getStatus(){
		return $this->status;
	}
	public function setStatus($status){
		$this->status = $status;
	}
}
//观者者抽象类
abstract class Observer{
	public function sendSms(){
	
	}
}
//具体的观察者
class ConcreteObserver extends Observer{
	private $name;
	private $status;
	private $objSubject;
	public function __construct($name, $objSubject){
		$this->name = $name;
		$this->objSubject = $objSubject;
	}
	public function sendSms(){
		$status = $this->objSubject->getStatus();
		echo '观察者'.$this->name.'收到的状态是'.$status.'<br>';
	}
}
//客户端/接口
$i = new I();
$i->setStatus('更换手机号码了。');
$friend1 = new ConcreteObserver('小明', $i);
$friend2 = new ConcreteObserver('小红', $i);
$friend3 = new ConcreteObserver('小黄', $i);
$i->add($friend1, 'sendSms');
$i->add($friend2, 'sendSms');
$i->add($friend3, 'sendSms');
$i->notice();
?>

建造者模式,也叫生成器模式。是设计模式的一种。某个复杂算法类,在方法调用上是顺序稳定的,但是具体属性不同,此时可以使用建造者模式。
建造者模式:一个复杂的对象,我们把它的构造和它的表示分离,可以实现同样的构造,而产生多种不同的表示,这种设计模式我们把它叫做建造者模式,也被成为生成器模式。顾名思义,在一个厂房中批量生成。
在定义和开发时,必须要满足:1、我们开发的类,允许被它的对象有多种不同的表示。2、当创建复杂对象的算法,应该独立于该对象的组成部分和该对象的装配方式。
在建造者模式这一的设计模式种,第一个类builder是各种创建方法的抽象接口。ConcreteBuilder调用Builder的接口来装配。提供对外的接口。ProductA是A产品类,调用ConcreteBuilder实现了具体的产品A的实现方法,也就是需要被构造的那个复杂的对象。Director就是我们的向导类,根据客户的需求生成产品A、产品B、产品C。
场景:麦当劳,汉堡和批萨,收银员就是向导类。以PHP为代码环境。

<?php
//麦当劳,抽象接口类
interface McDonald{
    public function yuanLiao();
    public function nieXingZhuang();
    public function jiaRe();
}
//汉堡,就是产品A类
class Hamburger implements McDonald{
    public function yuanLiao(){
        echo '采购原料:面+肉+生菜+酱';
        $this->separate();
    }
    public function nieXingZhuang(){
        echo '捏成蓬松的圆球形状';
        $this->separate();
    }
    public function jiaRe(){
        echo '加热10分种';
        $this->separate();
    }
    private function separate(){
        echo '<br>';
    }
}
//薯条,就是产品B类
class FrenchFries implements McDonald{
    public function yuanLiao(){
        echo '采购原料:土豆';
        $this->separate();
    }
    public function nieXingZhuang(){
        echo '切成细长条';
        $this->separate();
    }
    public function jiaRe(){
        echo '加热15分种';
        $this->separate();
    }
    private function separate(){
        echo '<br>';
    }
}
//收银员,就是向导类
class Cashier{
    public function createProduct($productObj){
        $productObj->yuanLiao();
        $productObj->nieXingZhuang();
        $productObj->jiaRe();
        return '制作完成,可以上桌了';
    }
}
//客户端/接口
$cashier = new Cashier();
$cashier->createProduct(new Hamburger());
$cashier->createProduct(new FrenchFries());
?>

外观模式其实非常容易用到,是对迪米特法则的一种应用:降低类的耦合度,添加中间件。也是对依赖倒转原则的完美体现:针对接口的编程。
外观模式:再次针对某个接口封装一个高层类,实现一个高层接口,按某种算法或使用方式整合底层接口类,使得底层的接口更加容易使用,也降低了底层接口和客户端的耦合度。
场景:调用数据库。以PHP为代码环境,以Mysql为数据库环境。

<?php
class MysqlDB{
    private $conn;
    public function __construct($host, $username, $password, $dbName){
        $this->conn($host, $username, $password);
        $this->selectDb($dbName);
    }
    private function conn($host, $username, $password){
        $this->conn = mysql_connect($host, $username, $password);
    }
    private function selectDb($dbName){
        mysql_select_db($dbName, $this->conn);
    }
    public function query($sql){
        return mysql_query($sql);
    }
    public function fetchArray($queryResult){
        return mysql_fetch_array($queryResult);
    }
	public function fetchAssoc($queryResult){
        return mysql_fetch_assoc($queryResutl);
    }
}
class Facade{
    private $mysqlObj;
	public function __construct($host, $username, $password, $dbName){
        $this->mysqlObj = new MysqlDB($host, $username, $password, $dbName);
    }
    public function get($tableName){
        $sql = 'SELECT * FROM ' . $tableName;
        $queryResult = $this->mysqlObj->query($sql);
        $fetchArr = $this->myqlObj->fetchAssoc($queryResult);
		return $fetchArr
    }
}
//客户端/接口
$obj = new Facade('localhost', 'root', 'root', 'db_name');
$list = $obj->get('user_info');
?>

常见的使用场景:
1、开发的初期阶段,有意识的建立中间件,将不同的两层分离,在层与层之间建立外观。
2、在开发阶段,某个类会根据需求的不断变更等原因使类变得更加复杂而庞大,增加一个外观类,使的使用者和这个庞大负责的类耦合降低。
3、历史遗留问题。需要用到遗留的复杂逻辑的类,直接调用是不好的,所以需要一个中间件(外观模式的外观类)来调用这个复杂类,而使用者调用外观类即可。
可以理解为,外观模式的外观类,是一个入口,使用者调用外观类,外观类调用底层的类。