标签归档:设计模式

设计模式

在软件工程中,设计模式(Design Pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。设计模式是描述在各种不同场景下,要怎么解决问题的一种方案。

常用设计模式
1 创建型(对象实例化)
抽象工厂模式(Abstract Factory)****
建造者模式(Builder)****
工厂方法模式(Factory Method)****
多例模式(Multiton)
对象池模式(Pool)
原型模式(Prototype)
简单工厂模式(Simple Factory)****
单例模式(Singleton)****
静态工厂模式(Static Factory) ****

2 结构型(类和对象的组合)
适配器模式(Adapter) ****
桥梁模式(Bridge)
组合模式(Composite)
数据映射模式(Data Mapper)
装饰模式(Decorator)
依赖注入模式(Dependency Injection) ****
门面模式(Facade) ****
流接口模式(Fluent Interface)
代理模式(Proxy) ****
注册模式(Registry)

3 行为型(类的对象间通信)
责任链模式(Chain Of Responsibilities) ****
命令行模式(Command)
迭代器模式(Iterator)
中介者模式(Mediator)
备忘录模式(Memento)
空对象模式(Null Object)
观察者模式(Observer) *****
规格模式(Specification)
状态模式(State)
策略模式(Strategy)
模板方法模式(Template Method)
访问者模式(Visitor)

4 其它
委托模式(Delegation)
服务定位器模式(Service Locator) ****
资源库模式(Repository)

来源:https://github.com/domnikl/DesignPatternsPHP

1.1 简单工厂模式、静态工厂模式、工厂方法模式、抽象工厂模式
简单工厂模式、静态工厂模式类似,都是直接约定使用某个方法生产产品;工厂方法模式是将生成产品的方法进行抽离,放入到一个抽象类中,工厂类继承该类并实现其中的工厂方法,本质上和简单工厂模式、静态工厂模式没有差别,不同是由于对生成产品的方法进行来抽离,方便产生不同类型的工厂;

抽象工厂模式与其它模式有较大不同,它是对工厂的抽象;在简单工厂模式、静态工厂模式、工厂方法模式中,工厂是和产品直接相关的,产品和工厂是不相关的(被抽象了,或者说只跟抽象工厂相关)。具体来说:抽象工厂不过是对不同类型的工厂进行抽象,比如某汽车公司可以生产轿车和汽车,由于复杂性,通常不会在一个工厂中生产,会分到轿车厂和汽车厂,但是轿车厂和汽车厂都具备了生产车的能力,当要生产汽车时,抽象工厂决定由汽车厂生产,用户并不知道汽车是由汽车厂生产的(产品和工厂不相关)。

抽象工厂模式通常用来解决较复杂的产品制造逻辑,绝大部分情况,简单工厂模式(包括静态工厂模式和工厂方法模式)可以很好适用。

Laravel中的Manager大量应用简单工厂模式(具体来说是工厂方法模式),比如Auth组件中,Guard管理:

// Illuminate\Contracts\Auth\Factory
<?php

namespace Illuminate\Contracts\Auth;

interface Factory
{
    /**
     * Get a guard instance by name.
     *
     * @param  string|null  $name
     * @return mixed
     */
    public function guard($name = null);

    /**
     * Set the default guard the factory should serve.
     *
     * @param  string  $name
     * @return void
     */
    public function shouldUse($name);
}


// Illuminate\Contracts\Auth\AuthManager
<?php

namespace Illuminate\Auth;

use Closure;
use InvalidArgumentException;
use Illuminate\Contracts\Auth\Factory as FactoryContract;

class AuthManager implements FactoryContract
{
    use CreatesUserProviders;

    public function guard($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();

        return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
    }
}

这里的guard方法就是工厂方法,AuthManager是工厂,它实现了guard方法,通过调用guard方法,可以得到不同的guard实例。当需要添加自定义的guard时,可以让AuthManager把自定义的产品类型(guard)添加进来,在调用时可以通过guard(“xxx”)取回自定义的guard实例。

1.2 建造者模式(Builder)

建造者模式将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。(对象创造过程进行抽离,把对象的创建变成标准步骤)。

关键点就是把步骤进行抽离,然后在面对不同类型对象的构建时,通过组合不同的步骤进行构建对象。

3 单例模式(Singleton)
单例模式的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个,同时这个类还必须提供一个访问该类的全局访问点。常见使用实例:数据库连接器;日志记录器(如果有多种用途使用多例模式);锁定文件。

<?php

/**
 * Singleton类
 */
class Singleton
{
    /**
     * @var Singleton reference to singleton instance
     */
    private static $instance;
    
    /**
     * 通过延迟加载(用到时才加载)获取实例
     *
     * @return self
     */
    public static function getInstance()
    {
        if (null === static::$instance) {
            static::$instance = new static;
        }

        return static::$instance;
    }

    /**
     * 构造函数私有,不允许在外部实例化
     *
     */
    private function __construct()
    {
    }

    /**
     * 防止对象实例被克隆
     *
     * @return void
     */
    private function __clone()
    {
    }

    /**
     * 防止被反序列化
     *
     * @return void
     */
    private function __wakeup()
    {
    }
}

由于PHP的运行模式的关系,单例设计模式并没有真正发挥到它应该起到的作用(只能锁定到请求作用域,无法应用到整个应用)。

2.1 适配器(Adapter)
适配器的存在,就是为了将已存在的东西(接口)转换成适合我们需要、能被我们所利用的东西。在现实生活中,适配器更多的是作为一个中间层来实现这种转换作用。比如电源适配器,它是用于电流变换(整流)的设备。

2.3 装饰模式(Decorator)
装饰器模式能够从一个对象的外部动态地给对象添加功能。

通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类这种方式并不可取。在面向对象的设计中,我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能。装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。装饰器模式的本质就是动态组合。动态是手段,组合才是目的。

常见的使用示例:Web服务层 —— 为 REST 服务提供 JSON 和 XML 装饰器。

2.3 依赖注入模式(Dependency Injection)

2.4 门面模式(Facade)
门面模式(Facade)又称外观模式,用于为子系统中的一组接口提供一个一致的界面。门面模式定义了一个高层接口,这个接口使得子系统更加容易使用:引入门面角色之后,用户只需要直接与门面角色交互,用户与子系统之间的复杂关系由门面角色来实现,从而降低了系统的耦合度。

2.5 流接口模式(Fluent Interface)

2.6 代理模式(Proxy)

3.1 责任链模式(Chain Of Responsibilities)
3.2 观察者模式(Observer)
3.3 迭代器模式(Iterator)

设计模式: 单态 和 工厂

单态模式
它们必须拥有一个构造函数并且必须被标记为private
它们拥有一个保存类的实例的静态成员变量。
它们拥有一个访问这个实例的公共的静态方法。

作为这一模式的一部分,必须创建一个空的私有的__clone()方法,以防止对象被复制或者克隆。

返回实例引用的这个方法通常被命名为getInstance(),这个方法必须是静态的,而且如果它还没有实例化,就必须进行实例化。getInstance()方法通过使用instanceof操作符和selft关键字,可以检测到类是否已经被初始化,如果保存实例的静态成员为空或者还不是类的自身的一个实例,那么这个实例将会被创建并保存到存放实例的变量中。

class Database{
	private $_db;
	static $_instance;
	private function __construct(){
	    $this->_db = pg_connect(‘dbname=example_db’);
        }
       private __clone(){};
       public static function getInstance(){
	    if(!(self::$_instance instanceof self)){
	          self::$_instance = new self();
            }
            return self::$_instance;
       }
}

工厂模式
工厂类是指包含了一个专门用来创建其它对象的类。
通常,工厂模式有一个关键的构造,即根据一般原则被命名为factory的静态方法。这个静态方法还可以接受任意数量的参数,并且必须返回一个对象。
[工厂使用模子来生产产品,模子就是类,产品就是类的实例,所以工厂类就是实例化其它类的类]
应用:
在使用数据库的应用程序中,工厂模式可以在以下两个方面起作用。
更容易支持各种不同的数据库平台。
如果软件是内部使用软件,那么在需要修改数据库时,可以很容易将应用程序移植到另外一个平台。

比如希望创建一个名为user的数据库表来测试它,这个表应该定义一个名为email的varchar类型的字段

interface IDatabaseBindings{
	public function userExists($email);
}

class PGSQL implements IDatabaseBindings{
	protected $_connection;

	public function __construct(){
		$this->_connection = pg_connect('dbname=example_db');
	}

	public function userExists($email){
		$emailEscaped = pg_escape_string($email);
		$query ="select 1 from users where email ='".$emailEscaped."'";
		if($result = pg_query($query,$this->_connection)){
			return (pg_num_rows($result) > 0)?true:false;
		}else{
			return false;
		}
	}
}

class MYSQL implements IDatabaseBindings{
	protected $_connection;
	public function __construct(){}
	public function userExists($email){}
}

class DatabaseFactory{
	public static function factory(){
		$type = loadtypefromconfigfile();
		switch($type){
			case 'PGSQL':
				return new PGSL();
				break;
			case 'MYSQL':
				return new MYSQL();
				break;
		}
	}
}

用法
$db = DatabaseFactory::factory();
$db->userExists(‘person@example.com’);

这个例子创建了两个实现类:一个是为PostgreSQL层实现的PGSQL类,另一个是为MySQL层实现的MySQL类,应用程序的其余部分将完全不知道它与何种类型的数据库打交道,只会基于IDatabaseBindings接口定义的规则直接与工厂返回的实例打交道。

永久链接: http://blog.ifeeline.com/788.html