作者归档:admin

PHP设计模式笔记:使用PHP实现工厂模式

PHP设计模式笔记:使用PHP实现工厂模式

【意图】
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使用一个类的实例化延迟到其子类【GOF95】

【工厂模式结构图】

工厂方法模式

工厂方法模式

【工厂模式中主要角色】
抽象产品(Product)角色:具体产品对象共有的父类或接口
具体产品(Concrete Product)角色:实现抽象产品角色所定义的接口,并且工厂方法模式所创建的每一个对象都是某具体产品对象的实例
抽象工厂(Creator)角色:模式中任何创建对象的工厂类都要实现这个接口,它声明了工厂方法,该方法返回一个Product类型的对象。
Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的的ConcreteProduct对象
具体工厂(Concrete Creator)角色:实现抽象工厂接口,具体工厂角色与应用逻辑相关,由应用程序直接调用以创建产品对象。

【工厂模式的优点和缺点】
工厂模式的优点
工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

工厂模式的缺点
客户可能仅仅为了创建一个特定的ConcreteProduct对象,就不得不创建一个Creator子类

【工厂模式适用场景】
1、当一个类不知道它所必须创建的对象的类的时候
2、当一个类希望由它的子类来指定它所创建的对象的时候
3、当类将创建对象的职责委托给多个帮助子类的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候

【工厂模式与其它模式】
抽象工厂模式(abstract factory模式):Abstract Factory模式经常使用工厂方法来实现
Template Method模式: 工厂方法通常在Template Methods中被调用

【工厂模式PHP示例】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
 
<?php
/**
 * 工厂模式 2010-06-25 sz
 * @author 胖子 phppan.p#gmail.com  http://www.phppan.com
 * 哥学社成员(http://www.blog-brother.com/)
 * @package design pattern
 */
 
/**
 * 抽象工厂角色
 */
interface Creator {
    public function factoryMethod();
}
 
/**
 * 具体工厂角色A
 */
class ConcreteCreatorA implements Creator {
 
    /**
     * 工厂方法 返回具体 产品A
     * @return ConcreteProductA
     */
    public function factoryMethod() {
        return new ConcreteProductA();
    }
}
 
/**
 * 具体工厂角色B
 */
class ConcreteCreatorB implements Creator {
 
    /**
     * 工厂方法 返回具体 产品B
     * @return ConcreteProductB
     */
    public function factoryMethod() {
        return new ConcreteProductB();
    }
}
 
/**
 * 抽象产品角色
 */
interface Product {
    public function operation();                                                                                    
}
 
/**
 * 具体产品角色A
 */
class ConcreteProductA implements Product {
 
    /**
     * 接口方法实现 输出特定字符串
     */
    public function operation() {
        echo 'ConcreteProductA <br />';
    }
}
 
/**
 * 具体产品角色B
 */
class ConcreteProductB implements Product {
 
    /**
     * 接口方法实现 输出特定字符串
     */
    public function operation() {
        echo 'ConcreteProductB <br />';
    }
}
 
class Client {
 
    /**
     * Main program.
     */
    public static function main() {
        $creatorA = new ConcreteCreatorA();
        $productA = $creatorA->factoryMethod();
        $productA->operation();
 
        $creatorB = new ConcreteCreatorB();
        $productB = $creatorB->factoryMethod();
        $productB->operation();
    }
 
}
 
Client::main();
?>

【工厂方法模式与简单工厂模式】
工厂方法模式与简单工厂模式再结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。
当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了”开放-封闭”原则。而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。
工厂方法模式退化后可以演变成简单工厂模式。

垃圾陷阱

问题描述
【Description】

卡门——农夫约翰极其珍视的一条Holsteins奶牛——已经落了到“垃圾井”中。“垃圾井”是农夫们扔垃圾的地方,它的深度为D (2 <= D <= 100)英尺。 卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。 每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。 假设卡门预先知道了每个垃圾扔下的时间t(0a then a:=b。

  这道题可以用DP解决。用l[i,j]表示掉下来i个垃圾后,卡门爬上的高度为j时她最长的寿命。显然l[0,0]=10。对于任一个状态l[i-1,j],若l[i-1,j]>=g[i].time,说明这个状态的卡门能够坚持到下一个垃圾下落。在这种情况下,按以下两种方法处理第i个垃圾,即进行状态转移:

吃掉第i个垃圾,即update(l[i,j],l[i-1,j]+g[i].life);

用第i个垃圾来垫高。令t=j+g[i].height,即把第i个垃圾用来垫高后卡门爬上的总高度。如果t>=d,则卡门于g[i].time时爬了出来,否则update(l[i,t],l[i-1,j])。

  若首次遇到某一个l[i,0]一次也没有赋值,说明卡门不可能坚持到第i个垃圾下落,则她最多可以存活的时间为l[i-1,0](即把前i-1个垃圾全吃掉后的寿命)。

  注意到在计算l数组的第i行时只用到了第i-1行,因此l数组可用滚动数组来实现。

【代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdio.h>
#include <string.h>
 
#define MAXN 101
#define max(a,b) a>b?a:b
 
typedef struct node
{
       int time, life, height;
}node;
 
int main()
{
 
       node a[MAXN], temp;
       int flag;
 
       int f[MAXN][MAXN * 10];
       int n, d, i, j, k, t, maxt, m;
 
       scanf("%d%d", &d, &n);
       maxt = 0;
 
       for (i = 1; i <= n; i++)
       {
              scanf("%d%d%d", &a[i].time, &a[i].life, &a[i].height);
       }
 
       for (i = 1; i < n; i++)
       {
 
              for (j = i + 1; j <= n; j++)
              {
 
                     if (a[i].time > a[j].time)                                                                 
                     {
                            temp = a[i];
                            a[i] = a[j];
                            a[j] = temp;
 
                     }
              }
       }
 
       memset(f, 0, sizeof(f));
 
       f[0][0] = 10;
       flag = 0;
       maxt = 0;
 
       for (i = 1; i <= n; i++)
       {
 
              m = 0;
              k = 0;
 
              for (j = 0; j <= maxt; j++)
              {
 
                     if (f[i - 1][j] >= a[i].time)
                     {
 
                            f[i][j] = max(f[i][j], f[i - 1][j] + a[i].life);
                            t = j + a[i].height;
 
                            if (t >= d)
                            {
                                   flag = a[i].time;
                                   break;
                            }
 
                            if (t > m)
                                   m = t;
 
                            f[i][t] = max(f[i][t], f[i - 1][j]);
                            k++;
                     }
              }
 
              if (k == 0)
                     break;
 
              if (flag != 0)
                     break;
 
              maxt = m;
       }
 
       if (flag != 0)
              printf("%d\n", flag);
       else
       {
              printf("%d\n", f[i - 1][0]);
       }
       return 0;
}

应该是5年前的代码了,从以前的百度blog中转了过来

PHP设计模式笔记:使用PHP实现原型模式

PHP设计模式笔记:使用PHP实现原型模式

【意图】
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象

【原型模式结构图】
Prototype

【原型模式中主要角色】
抽象原型(Prototype)角色:声明一个克隆自身的接口

具体原型(Concrete Prototype)角色:实现一个克隆自身的操作

【原型模式的优点和缺点】
Prototype模式优点:
1、可以在运行时刻增加和删除产品
2、可以改变值以指定新对象
3、可以改变结构以指定新对象
4、减少子类的构造
5、用类动态配置应用

Prototype模式的缺点:
Prototype模式的最主要缺点就是每一个类必须配备一个克隆方法。
而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事。

【原型模式适用场景】
1、当一个系统应该独立于它的产品创建、构成和表示时,要使用Prototype模式
2、当要实例化的类是在运行时刻指定时,例如动态加载
3、为了避免创建一个与产品类层次平等的工厂类层次时;
4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些

【原型模式与其它模式】
抽象工厂模式(abstract factory模式):Abstract Factory模式与Prototype模式在某种方面是相互竞争的。但是也可以一起使用

【原型模式PHP示例】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 
<?php
/**
 * 原型模式 2010-06-27 sz
 * @author phppan.p#gmail.com  http://www.phppan.com
 * 哥学社成员(http://www.blog-brother.com/)
 * @package design pattern
 */
 
/**
 * 抽象原型角色
 */
interface Prototype {
    public function copy();
}
 
/**
 * 具体原型角色
 */
class ConcretePrototype implements Prototype{
 
    private  $_name;
 
    public function __construct($name) {
        $this->_name = $name;
    }
 
    public function setName($name) {
        $this->_name = $name;
    }
 
    public function getName() {
        return $this->_name;
    }
 
    public function copy() {
       /* 深拷贝实现
        $serialize_obj = serialize($this);  //  序列化
        $clone_obj = unserialize($serialize_obj);   //  反序列化                                                     
        return $clone_obj;
        */
        return clone $this;     //  浅拷贝
    }
}
 
/**
 * 测试深拷贝用的引用类
 */
class Demo {
    public $array;
}
 
class Client {
 
     /**
     * Main program.
     */
    public static function main() {
 
        $demo = new Demo();
        $demo->array = array(1, 2);
        $object1 = new ConcretePrototype($demo);
        $object2 = $object1->copy();
 
        var_dump($object1->getName());
        echo '<br />';
        var_dump($object2->getName());
        echo '<br />';
 
        $demo->array = array(3, 4);
        var_dump($object1->getName());
        echo '<br />';
        var_dump($object2->getName());
        echo '<br />';
 
    }
 
}
 
Client::main();
?>

【浅拷贝与深拷贝】

浅拷贝
被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象。
即 浅拷贝只负责当前对象实例,对引用的对象不做拷贝。

深拷贝
被拷贝对象的所有的变量都含有与原来对象相同的值,除了那些引用其他对象的变量。那些引用其他对象的变量将指向一个被拷贝的新对象,而不再是原有那些被引用对象。
即 深拷贝把要拷贝的对象所引用的对象也都拷贝了一次,而这种对被引用到的对象拷贝叫做间接拷贝。
深拷贝要深入到多少层,是一个不确定的问题。
在决定以深拷贝的方式拷贝一个对象的时候,必须决定对间接拷贝的对象是采取浅拷贝还是深拷贝还是继续采用深拷贝。
因此,在采取深拷贝时,需要决定多深才算深。此外,在深拷贝的过程中,很可能会出现循环引用的问题。

利用序列化来做深拷贝
利用序列化来做深拷贝,把对象写到流里的过程是序列化(Serilization)过程,但在业界又将串行化这一过程形象的称为“冷冻”或“腌咸菜”过程;
而把对象从流中读出来的过程则叫做反序列化(Deserialization)过程,也称为“解冻”或“回鲜”过程。
在PHP中使用serialize和unserialize函数实现序列化和反序列化

在上面的代码中的注释就是一个先序列化再反序列化实现深拷贝的过程