标签 设计模式 下的文章

建造者模式,也叫生成器模式。是设计模式的一种。某个复杂算法类,在方法调用上是顺序稳定的,但是具体属性不同,此时可以使用建造者模式。
建造者模式:一个复杂的对象,我们把它的构造和它的表示分离,可以实现同样的构造,而产生多种不同的表示,这种设计模式我们把它叫做建造者模式,也被成为生成器模式。顾名思义,在一个厂房中批量生成。
在定义和开发时,必须要满足: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、历史遗留问题。需要用到遗留的复杂逻辑的类,直接调用是不好的,所以需要一个中间件(外观模式的外观类)来调用这个复杂类,而使用者调用外观类即可。
可以理解为,外观模式的外观类,是一个入口,使用者调用外观类,外观类调用底层的类。

面向对象的特性之一:封装。不需要知道具体如何实现的细节,只需要调用某个类的方法,得到预期的结果。尽可能少的使用public,降低成员的访问权限。可以更好降低类与类之间的耦合度。程序设计时,修改一个越弱耦合的类,对系统造成的影响就会越小,耦合度越低,越利于复用。这就是迪米特法则的根本思想。
依赖接口而不是依赖实现,在弱耦合、低权限的基础上,完全不需要关心接口的实现细节,这也就是依赖倒转原则。面向对象的原则和面向对象的特性是不对立的。
迪米特法则:如果两个类,不需要直接进行两个类之间的通信,那么,这两个类就不应该直接发生作用和求情,如果一个类在特定条件下需要调用另一个类,那么,可以通过第三个类来实现,转发这个调用。
是不是又用点像代理模式?代理模式是针对对象的,代理类实例化真实类,调用真实类的方法。而迪米特法则是一个类调用另一个类,然后这个另一个类再调用另另一个类。

模板方法模式,是最为常见,也是使用最为广泛的一种设计模式,很多程序猿都不知道,自己随便写的代码,也是一种设计模式。如果只能学习一种设计模式的话,那么就应该学习模板模式。
模板模式:在一个方法里定义算法的骨架,将一些步骤延迟到其子类。顾名思义,模板模式,就是有一个固定的,现成的模板,往里面套东西呗。比如PPT,WORD,EXCEL等,Microsoft为我们提供了大量的模板。可以直接套用,也可以略做修改。总之,比我们自己全新做要省很多事儿。
抽出多个类的共同特性,成为一个父类,父类根据需求封装好一个算法骨架,然后子类调用父类即可。
以PHP为代码环境,

<?php
class TestPaper{
    public $name;
    public $classes;
    public function __construct($name, $classes){
        $this->name = $name;
        $this->classes = $classes;
    }
    public function display(){
        echo '姓名:' . $this->name . ', 班级:' . $this->classes;
        $this->separate();
    }
    public function title1($answer){
        echo '题目一:******';
        echo '答案:' . $this->answer($answer);
        $this->separate();
    }
    public function title2($answer){
        echo '题目二:******';
        echo '答案:' . $this->answer($answer);
        $this->separate();
    }
    public function answer($answer){
        return $answer;
    }
    public function separate(){
        echo '<br>';
    }
}
class studentA extends TestPaper{
    public function __construct($name, $classes){
        parent::__construct($name, $classes);
    }
    public function answerTestPaper(){
        $this->display();
        $this->title1('C');
        $this->title1('B');
    }
}
class studentB extends TestPaper{
    public function __construct($name, $classes){
        parent::__construct($name, $classes);
    }
    public function answerTestPaper(){
        $this->display();
        $this->title1('A');
        $this->title1('D');
    }
}
$studentA = new studentA('小明', '一');
$studentA->answerTestPaper();
$studentB = new studentB('小红', '二');
$studentB->answerTestPaper();
?>

原型模式提取重复功能,避免了程序员喜欢复制粘贴的坏习惯。设计模式中的原型模式就是,用原型实例指定创建对象的重力,通过拷贝这些原型来创建新的对象从一个对象再创建另外一个可定制的对象,而且不需要知道创建的任何细节。
浅复制 VS 深复制:
浅复制是对数字,字符串等类型进行传值复制,而对对象来讲是引用复制,即只是对内存地址进行赋值而不是新建一个对象的变量。在浅复制中,对一个对象的属性改变,另一个对象的该属性也会被改变,类比于C语言的指针,PHP在调用方法时&$var的传递。
以PHP为代码环境。

<?php
//家庭类
class Home{
    public $money;
    public function __construct($money){
        $this->money = $money;
	}
}
//家庭成员类
class member{
    public $id;
    public $name;
    public $obj;
    public function __construct($id, $name, Home $obj){
        $this->setId($id);
        $this->setName($name);
		$this->obj = $obj;
    }
    public function setId($id){
        $this->id = $id;
    }
	public function setName($name){
        $this->name = $name;
    }
    public function display(){
	    echo 'ID为' . $this->id . ',名称为' . $this->name . ',资产为' . $this->obj->money . '<br>';
    }
	public function __clone(){
        //深度复制(克隆),因为克隆只能克隆数字,字符串等,对对象变量是引用传值。	
        $this->obj = clone $this->obj;
    }
}
//客户端/接口
$obj1 = new member(1, '小轩', new Home('10000'));
$obj1->display();
$obj2 = clone $obj1;
$obj2->setId(2);
$obj2->setName('小玮');
$obj2->obj->money = 2000;
$obj2->display();
//根据这句输出可以看到,对象1和对象2值是不一样的,删掉上面的注释部分再看,又是一样的了,这就是深复制和浅复制。
$obj1->display();
?>