澳门新浦京电子游戏模式(一)javascript设计模式

本文主要讨论下Web开发中,准确而言,是PHP开发中的相关的设计模式及其应用。有经验的开发者肯定对于设计模式非常熟悉,但是本文主要是针对那些初级的开发者。首先我们要搞清楚到底什么是设计模式,设计模式并不是一种用来解释的模式,它们并不是像链表那样的常见的数据结构,也不是某种特殊的应用或者框架设计。事实上,设计模式的解释如下:

模式有三种:Architectural Pattern、Design Pattern、Coding
Pattern,即:框架模式、设计模式、编程模式。本文主要讲解javascript中的设计模式,好的设计模式能够提高代码的重用性,可读性,使代码更容易的维护和扩展。本文适合有一点javascript基础,对javascript的概念有所了解。

澳门新浦京电子游戏 1

descriptions of communicating objects and classes that are customized
to solve a general design problem in a particular context.

一、单例模式:

 单例模式是javascript中最常用的模式,它是将自己的代码放在一个命名空间下,这样的好处是可以减少使用全局变量,在多人协同开发时也能避免命名冲突等问题。这样的好处是维护起来非常方便,如下例:

1 var m = {
2     name: 'dog',
3     action: function() {
4         console.log(this.name);
5     }
6 };
7 m.action();//调用

 

或者

1 var dog = function() {
2     this.name = 'dog';
3     this.action = function() {
4         return console.log(this.name);
5     };
6     action();
7 };
8 dog(); //调用

 

  • 官方用到的几种设计模式
    • 代理模式
    • 观察者模式
    • 单例模式(Singleton)
    • 工厂模式
    • 策略模式
    • 装饰模式(Decorator)
    • 适配器模式
    • MVC及一些衍生设计模式

另一方面,设计模式提供了一种广泛的可重用的方式来解决我们日常编程中常常遇见的问题。设计模式并不一定就是一个类库或者第三方框架,它们更多的表现为一种思想并且广泛地应用在系统中。它们也表现为一种模式或者模板,可以在多个不同的场景下用于解决问题。设计模式可以用于加速开发,并且将很多大的想法或者设计以一种简单地方式实现。当然,虽然设计模式在开发中很有作用,但是千万要避免在不适当的场景误用它们。

工厂模式:

工厂模式就是将对象的方法创建交给外部对象,这样的好处就是解决了对象之间的相互影响、即耦合,避免了使用new来实例化对象,有助于创建模块化的代码,维护起来也方便。 工厂模式分为简单工厂模式和抽象工厂模式,下面介绍简单工厂模式:

1 var m = {};
2 m.action = function() {
3     console.log('dog');
4 };
5 var demo = function() {
6     m.action();
7 };
8 demo()//调用

 

抽象工厂模式先设计一个抽象类,这个类不能被实例化,只能用来派生子类,最后通过对子类的扩展实现工厂方法。如下:

 1 var f = function() {};
 2 f.prototype = {
 3     c: function() {
 4         throw new Error('can't use this method');//如果调用此方法会报错,因为它是用来派生子类不能实例化
 5     }
 6 };
 7 var e = function() {
 8     f.call(this);
 9 }
10 e.prototype = new f();
11 e.prototype.constructor = e;
12 e.prototype.c = function() {
13     console.log('this method is redefine');
14 }
15 // 调用
16 var demo = new e();
17 demo.c();

 

官方的用法总是我们很关心、也是值得学习的

目前常见的设计模式主要有23种,根据使用目标的不同可以分为以下三大类:

桥接模式:

桥接模式是将抽象与实现隔离,一遍二者独立变化。在设计一个javascript
API的时候,它可以用来弱化类和对象之间的耦合。它还可以用来把多个类联接在一起。例如:

 1 var class1 = function(a,b,c) {
 2     this.a = a;
 3     this.b = b;
 4     this.c = c;
 5 };
 6 var class2 = function(d) {
 7     this.d = d;
 8 };
 9 var demo = function(a,b,c,d) {
10     this.one = new Class1(a,b,c);
11     this.two = new Class2(d);
12 };

 

代理模式(Proxy Pattern)

当一个类的某些功能需要由别的类来实现、但是又不确定具体会是哪个类实现。

有两个主体:委托者(方法调用者)、代理者(方法实现者)。

  • 创建模式:用于创建对象从而将某个对象从实现中解耦合。
  • 架构模式:用于在不同的对象之间构造大的对象结构。
  • 行为模式:用于在不同的对象之间管理算法、关系以及职责。

组合模式:

组合模式可以用一条命令在多个对象上激发复杂的或递归的行为。好处是可以用同样的发放处理对象的集合与其中的特定子对象,也可以用来把一批子对象组织成树形结构,并且使整个树都可被遍历。如下:

 1 // DynamicGallery Class
 2   var DynamicGallery =function (id) { // 实现Composite,GalleryItem组合对象类 
 3      this.children = [];
 4      this.element = document.createElement('div');
 5      this.element.id = id;
 6      this.element.className ='dynamic-gallery';
 7   }
 8   DynamicGallery.prototype = {
 9      // 实现Composite组合对象接口 
10      add: function (child) {
11         this.children.push(child);
12         this.element.appendChild(child.getElement());
13      },
14      remove: function (child) {
15         for (var node, i =0; node =this.getChild(i); i++) {
16            if (node == child) {
17               this.children.splice(i, 1);
18               break;
19            }
20         }
21         this.element.removeChild(child.getElement());
22      },
23      getChild: function (i) {
24         returnthis.children[i];
25      },
26      // 实现DynamicGallery组合对象接口 
27      hide: function () {
28         for (var node, i =0; node =this.getChild(i); i++) {
29            node.hide();
30         }
31         this.element.style.display ='none';
32      },
33      show: function () {
34         this.element.style.display ='block';
35         for (var node, i =0; node = getChild(i); i++) {
36            node.show();
37         }
38      },
39      // 帮助方法 
40      getElement: function () {
41         returnthis.element;
42      }
43   }

 

 1 var GalleryImage =function (src) { // 实现Composite和GalleryItem组合对象中所定义的方法 
 2      this.element = document.createElement('img');
 3      this.element.className ='gallery-image';
 4      this.element.src = src;
 5   }
 6   GalleryImage.prototype = {
 7      // 实现Composite接口 
 8      // 这些是叶结点,所以我们不用实现这些方法,我们只需要定义即可 
 9      add: function () { },
10      remove: function () { },
11      getChild: function () { },
12      // 实现GalleryItem接口 
13      hide: function () {
14         this.element.style.display ='none';
15      },
16      show: function () {
17         this.element.style.display ='';
18      },
19      // 帮助方法 
20      getElement: function () {
21         returnthis.element;
22      }
23   }

 1 var topGallery =new DynamicGallery('top-gallery'); 
 2   topGallery.add(new GalleryImage('/img/image-1.jpg')); 
 3   topGallery.add(new GalleryImage('/img/image-2.jpg')); 
 4   topGallery.add(new GalleryImage('/img/image-3.jpg')); 
 5   var vacationPhotos =new DyamicGallery('vacation-photos'); 
 6   for(var i =0, i <30; i++){ 
 7     vacationPhotos.add(new GalleryImage('/img/vac/image-'+ i +'.jpg')); 
 8   } 
 9   topGallery.add(vacationPhotos); 
10   topGallery.show(); 
11   vacationPhotos.hide();

 

Cocoa下的应用:

UITableView、UIAlertView、NSURLSession等等

Creational Patterns

门面模式:

门面模式常常是开发人员最亲密的朋友,他几乎是所有javascript库的核心原则。门面模式有两个作用:一是简化类的接口;二是消除类与使用它的客户代码之间的耦合。示例如下:

 1 function a() {
 2 
 3 }
 4 function b() {
 5 
 6 }
 7 function ab() {
 8     a();
 9     b();
10 }

 

观察者模式

主要负责对象间的通讯。

观察者注册自己感兴趣的事件、被观察者不需要知道观察者的存在。

Singleton(单例模式)

单例模式是最常见的模式之一,在Web应用的开发中,常常用于允许在运行时为某个特定的类创建一个可访问的实例。

<?php
/**
 * Singleton class
 */
final class Product
{

    /**
     * @var self
     */
    private static $instance;

    /**
     * @var mixed
     */
    public $mix;

    /**
     * Return self instance
     *
     * @return self
     */
    public static function getInstance() {
        if (!(self::$instance instanceof self)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
    }

    private function __clone() {
    }
}

$firstProduct = Product::getInstance();
$secondProduct = Product::getInstance();

$firstProduct->mix = 'test';
$secondProduct->mix = 'example';

print_r($firstProduct->mix);
// example
print_r($secondProduct->mix);
// example

在很多情况下,需要为系统中的多个类创建单例的构造方式,这样,可以建立一个通用的抽象父工厂方法:

<?php

abstract class FactoryAbstract {

    protected static $instances = array();

    public static function getInstance() {
        $className = static::getClassName();
        if (!(self::$instances[$className] instanceof $className)) {
            self::$instances[$className] = new $className();
        }
        return self::$instances[$className];
    }

    public static function removeInstance() {
        $className = static::getClassName();
        if (array_key_exists($className, self::$instances)) {
            unset(self::$instances[$className]);
        }
    }

    final protected static function getClassName() {
        return get_called_class();
    }

    protected function __construct() { }

    final protected function __clone() { }
}

abstract class Factory extends FactoryAbstract {

    final public static function getInstance() {
        return parent::getInstance();
    }

    final public static function removeInstance() {
        parent::removeInstance();
    }
}
// using:

class FirstProduct extends Factory {
    public $a = [];
}
class SecondProduct extends FirstProduct {
}

FirstProduct::getInstance()->a[] = 1;
SecondProduct::getInstance()->a[] = 2;
FirstProduct::getInstance()->a[] = 3;
SecondProduct::getInstance()->a[] = 4;

print_r(FirstProduct::getInstance()->a);
// array(1, 3)
print_r(SecondProduct::getInstance()->a);
// array(2, 4)

适配器模式:

适配器模式可以用来在现有接口和不兼容的类之间进行适配。从表面上看,适配器模式很像门面模式,都对别的对象进行包装并改变其呈现的接口。二者的区别在与它们如何改变接口,门面元素展现的是一个简化的接口,它并不提供额外的选择,而且有时为了方便完成常见任务它还会做出一些假定。而适配器则要把一个接口转换为另一个接口,它并不会过滤某些能力,也不会简化接口。

 1 var str = {
 2     a: 'a',
 3     b: 'b',
 4     c: 'c'
 5 };
 6 function i(s1,s2,s3) {
 7     console.log(s1 + ',' + s2 + ',' + s3);
 8 }
 9 function demo(o) {
10     i(o.a,o.b,o.c);
11 }

 

Cocoa下的应用:

键盘升降(UIKeyboardWillShowNotificationUIKeyboardWillHideNotification)、前后台切换(name:UIApplicationDidEnterBackgroundNotificationUIApplicationDidBecomeActiveNotification)等等

具体应用:下载进度条、表单填写状态的更新。不过实际上cocoa并没有给我们暴露直接使用KVO的例子。

Registry

注册台模式并不是很常见,它也不是一个典型的创建模式,只是为了利用静态方法更方便的存取数据。

<?php
/**
* Registry class
*/
class Package {

    protected static $data = array();

    public static function set($key, $value) {
        self::$data[$key] = $value;
    }

    public static function get($key) {
        return isset(self::$data[$key]) ? self::$data[$key] : null;
    }

    final public static function removeObject($key) {
        if (array_key_exists($key, self::$data)) {
            unset(self::$data[$key]);
        }
    }
}

Package::set('name', 'Package name');

print_r(Package::get('name'));
// Package name

装饰者模式:

装饰者模式可用来透明地把对象包装在具有同样接口的另一个对象之中,装饰者可以用于为对象添加功能,可以用来代替大量子类。装饰者模式和组合模式有很多共同点,它们都与所包装的对象实现统一的接口并且会把任何方法条用传递给这些对象。可是组合模式用于把众多子对象组织为一个整体,而装饰者模式用于在不修改现有对象或从派生子类的前提下为其添加方法。如下:

1 var m = {};
2 m.child = {};
3 m.child.one = function() {};
4 m.child.two = function() {};

 

单例模式(Singleton)

主要用于共享资源、并且确保该实例只被初始化一次。

Factory(工厂模式)

工厂模式是另一种非常常用的模式,正如其名字所示:确实是对象实例的生产工厂。某些意义上,工厂模式提供了通用的方法有助于我们去获取对象,而不需要关心其具体的内在的实现。

<?php

interface Factory {
    public function getProduct();
}

interface Product {
    public function getName();
}

class FirstFactory implements Factory {

    public function getProduct() {
        return new FirstProduct();
    }
}

class SecondFactory implements Factory {

    public function getProduct() {
        return new SecondProduct();
    }
}

class FirstProduct implements Product {

    public function getName() {
        return 'The first product';
    }
}

class SecondProduct implements Product {

    public function getName() {
        return 'Second product';
    }
}

$factory = new FirstFactory();
$firstProduct = $factory->getProduct();
$factory = new SecondFactory();
$secondProduct = $factory->getProduct();

print_r($firstProduct->getName());
// The first product
print_r($secondProduct->getName());
// Second product

 享元模式:

 享元模式最适合于解决因创建大量类似对象而累及性能的问题。通过把大量独立对象转化为少量共享对象,可以降低运行web应用程序所需的资源数量。

javascript设计模式中的示例:

 1 //汽车登记示例
 2   var Car =function(make,model,year,owner,tag,renewDate){
 3     this.make=make;
 4     this.model=model;
 5     this.year=year;
 6     this.owner=owner;
 7     this.tag=tag;
 8     this.renewDate=renewDate;
 9   }
10   Car.prototype = {
11     getMake:function(){
12       returnthis.make;
13     },
14     getModel:function(){
15       returnthis.model;
16     },
17     getYear:function(){
18       returnthis.year;
19     },
20     transferOwner:function(owner,tag,renewDate){
21       this.owner=owner;
22       this.tag=tag;
23       this.renewDate=renewDate;
24     },
25     renewRegistration:function(renewDate){
26       this.renewDate=renewDate;
27     }
28   }
29   //数据量小到没多大的影响,数据量大的时候对计算机内存会产生压力,下面介绍享元模式优化后
30   //包含核心数据的Car类
31   var Car=function(make,model,year){
32     this.make=make;
33     this.model=model;
34     this.year=year;
35   }
36   Car.prototype={
37     getMake:function(){
38       returnthis.make;
39     },
40     getModel:function(){
41       returnthis.model;
42     },
43     getYear:function(){
44       returnthis.year;
45     }
46   }
47   //中间对象,用来实例化Car类
48   var CarFactory=(function(){
49     var createdCars = {};
50     return {
51       createCar:function(make,model,year){
52         var car=createdCars[make+"-"+model+"-"+year];
53         return car ? car : createdCars[make +'-'+ model +'-'+ year] =(new Car(make,model,year));
54       }
55     }
56   })();
57   //数据工厂,用来处理Car的实例化和整合附加数据
58   var CarRecordManager = (function() {
59     var carRecordDatabase = {};
60     return {
61       addCarRecord:function(make,model,year,owner,tag,renewDate){
62         var car = CarFactory.createCar(make, model, year);
63         carRecordDatabase[tag]={
64           owner:owner,
65           tag:tag,
66           renewDate:renewDate,
67           car:car
68       }
69     },
70       transferOwnership:function(tag, newOwner, newTag, newRenewDate){
71         var record=carRecordDatabase[tag];
72         record.owner = newOwner;
73         record.tag = newTag;
74         record.renewDate = newRenewDate;
75       },
76       renewRegistration:function(tag,newRenewDate){
77         carRecordDatabase[tag].renewDate=newRenewDate;
78       },
79       getCarInfo:function(tag){
80         return carRecordDatabase[tag];
81       }
82     }
83   })();

 

Cocoa下的应用:

[NSUserDefaults standardUserDefaults]
[UIApplication sharedApplication][UIScreen mainScreen][NSFileManager defaultManager]等等。

AbstractFactory(抽象工厂模式)

有些情况下我们需要根据不同的选择逻辑提供不同的构造工厂,而对于多个工厂而言需要一个统一的抽象工厂:

<?php

class Config {
    public static $factory = 1;
}

interface Product {
    public function getName();
}

abstract class AbstractFactory {

    public static function getFactory() {
        switch (Config::$factory) {
            case 1:
                return new FirstFactory();
            case 2:
                return new SecondFactory();
        }
        throw new Exception('Bad config');
    }

    abstract public function getProduct();
}

class FirstFactory extends AbstractFactory {
    public function getProduct() {
        return new FirstProduct();
    }
}
class FirstProduct implements Product {
    public function getName() {
        return 'The product from the first factory';
    }
}

class SecondFactory extends AbstractFactory {
    public function getProduct() {
        return new SecondProduct();
    }
}
class SecondProduct implements Product {
    public function getName() {
        return 'The product from second factory';
    }
}

$firstProduct = AbstractFactory::getFactory()->getProduct();
Config::$factory = 2;
$secondProduct = AbstractFactory::getFactory()->getProduct();

print_r($firstProduct->getName());
// The first product from the first factory
print_r($secondProduct->getName());
// Second product from second factory

代理模式:

代理是一个对象,它可以用来控制对另一个对象的访问。它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象。代理模式适合处理实例化比较费时的本体,也适合处理那些需要较长时间才能把数据载入用户界面的类。

javascript设计模式中的示例:

 1 var Publication =new Interface('Publication', ['getIsbn', 'setIsbn', 'getTitle', 'setTitle', 'getAuthor', 'setAuthor', 'display']);
 2   var Book =function(isbn, title, author) {
 3       //...
 4   } 
 5   // implements Publication
 6   implements(Book,Publication);
 7 
 8   /* Library interface. */
 9   var Library =new Interface('Library', ['findBooks', 'checkoutBook', 'returnBook']);
10 
11   /* PublicLibrary class. */
12   var PublicLibrary =function(books) {
13       //...
14   };
15   // implements Library
16   implements(PublicLibrary,Library); 
17 
18   PublicLibrary.prototype = {
19       findBooks: function(searchString) {
20          //...
21       },
22       checkoutBook: function(book) {
23           //...
24       },
25       returnBook: function(book) {
26           //...
27       }
28   };
29 
30   /* PublicLibraryProxy class, a useless proxy. */
31   var PublicLibraryProxy =function(catalog) { 
32       this.library =new PublicLibrary(catalog);
33   };
34   // implements Library
35   implements(PublicLibraryProxy,Library);
36 
37   PublicLibraryProxy.prototype = {
38       findBooks: function(searchString) {
39           returnthis.library.findBooks(searchString);
40       },
41       checkoutBook: function(book) {
42           returnthis.library.checkoutBook(book);
43       },
44       returnBook: function(book) {
45           returnthis.library.returnBook(book);
46       }
47   };

 

工厂模式

专门定义一个类来负责创建其他类的实例、被创建的实例常常具有共同的父类。

Object pool(对象池)

对象池可以用于构造并且存放一系列的对象并在需要时获取调用:

class Factory {

    protected static $products = array();

    public static function pushProduct(Product $product) {
        self::$products[$product->getId()] = $product;
    }

    public static function getProduct($id) {
        return isset(self::$products[$id]) ? self::$products[$id] : null;
    }

    public static function removeProduct($id) {
        if (array_key_exists($id, self::$products)) {
            unset(self::$products[$id]);
        }
    }
}

Factory::pushProduct(new Product('first'));
Factory::pushProduct(new Product('second'));

print_r(Factory::getProduct('first')->getId());
// first
print_r(Factory::getProduct('second')->getId());
// second

观察者模式:

观察者模式是一种管理人与其任务之间的关系的得力工具。观察者模式中存在两个角色:观察者和被观察者。这种模式的好处是你可以对程序中某个对象的状态进行观察,并且在其发生改变时能够得到通知。

 1   var f1 =function(){
 2      //code
 3   }
 4   var f2 =function(){
 5      //code
 6   }
 7   addEvent(element,'click',f1);
 8   addEvent(element,'click',f2)
 9 
10 
11   element.onclick = f1;
12   element.onclick = f2;

 

工厂模式分为三种:简单工厂模式、工厂模式、抽象工厂模式。

由一个工厂类、根据传入的参数(通常是枚举)、动态的决定创建出哪一个产品类的实例。

适用于负责创建的对象比较少的情况下使用、简单工厂的稳定性和可扩展性会随着数量的增加而下降。

Lazy Initialization(延迟初始化)

对于某个变量的延迟初始化也是常常被用到的,对于一个类而言往往并不知道它的哪个功能会被用到,而部分功能往往是仅仅被需要使用一次。

<?php

interface Product {
    public function getName();
}

class Factory {

    protected $firstProduct;
    protected $secondProduct;

    public function getFirstProduct() {
        if (!$this->firstProduct) {
            $this->firstProduct = new FirstProduct();
        }
        return $this->firstProduct;
    }

    public function getSecondProduct() {
        if (!$this->secondProduct) {
            $this->secondProduct = new SecondProduct();
        }
        return $this->secondProduct;
    }
}

class FirstProduct implements Product {
    public function getName() {
        return 'The first product';
    }
}

class SecondProduct implements Product {
    public function getName() {
        return 'Second product';
    }
}

$factory = new Factory();

print_r($factory->getFirstProduct()->getName());
// The first product
print_r($factory->getSecondProduct()->getName());
// Second product
print_r($factory->getFirstProduct()->getName());
// The first product

命令模式:

命令模式可以用来对方法调用进行参数化处理和传送,经这样处理过的方法调用可以在任何需要的时候执行。好处是可以用来消除调用操作的对象和实现操作的对象之间的耦合,使对象间的互动方式更高的模块化。这为各种具体的类更换带来了极大的灵活性。

 1 car Calculator={
 2      add:function(x,y){
 3         return x+y;
 4      },
 5      substract:function(x,y){
 6         return x-y;
 7      },
 8      multiply:function(x,y){
 9         return x*y;
10      },
11      divide:function(x,y){
12         return x/y;
13      }
14   }
15   Calculator.calc =function(command){
16      return Calculator[command.type](command.op1,command.opd2)
17   };
18   Calculator.calc({type:'add',op1:1,op2:1});
19   Calculator.calc({type:'substract',op1:5,op2:2});
20   Calculator.calc({type:'multiply',op1:5,op2:2});
21   Calculator.calc({type:'divide',op1:8,op2:4});

 

需要以下三个元素:

1.
工厂(Factory
)角色接受客户端的请求、通过请求负责创建相应的产品对象。2.
抽象产品(Abstract
Product
)工厂模式所创建对象的父类或是共同拥有的接口、可是抽象类或接口<也就是协议>。3.
具体产品(ConcreteProduct
)工厂模式所创建的对象都是这个产品实例。

Prototype(原型模式)

有些时候,部分对象需要被初始化多次。而特别是在如果初始化需要耗费大量时间与资源的时候进行预初始化并且存储下这些对象。

<?php

interface Product {
}

class Factory {

    private $product;

    public function __construct(Product $product) {
        $this->product = $product;
    }

    public function getProduct() {
        return clone $this->product;
    }
}

class SomeProduct implements Product {
    public $name;
}

$prototypeFactory = new Factory(new SomeProduct());

$firstProduct = $prototypeFactory->getProduct();
$firstProduct->name = 'The first product';

$secondProduct = $prototypeFactory->getProduct();
$secondProduct->name = 'Second product';

print_r($firstProduct->name);
// The first product
print_r($secondProduct->name);
// Second product

职责链模式:

职责链模式是通过实现一个由隐式地请求进行处理对象组成的链而做到的。可以用来消除请求的发送者和接收者之间的耦合

javascript内部就使用了这种模式来处理事件捕获和冒泡的问题。

职责链由多个不同类型的对象组成:发送者是发出请求的对象,而接收者则是接收请求并且对其进行处理或传递的对象,请求本身有时也是一个对象,它封装着与操作有关的所有数据。其典型的流程大致是:

  1. 发送者知道链中第一个接收者,它向这个接收者发出请求。
  2. 每一个接收者都对请求进行分析,然后要么处理它,要么将其往下传。
  3. 每一个接收者知道的其他对象只有一个,即它在链中的下家。
  4. 如果没有任何接收者处理请求,那么请求将从链上离开,不同的实现对此也有不同的反应,一般会抛出一个错误。
工厂实现:
//AnimalHouse+ animalWithType:(AnimalType)type { Animal *animal = nil; if (type == AnimalTypeDog) {//狗 animal = [[Dog alloc] init]; } else if (type == AnimalTypeCat) { animal = [[Cat alloc] init]; } else if (type == AnimalTypeSheep) { animal = [[Sheep alloc] init]; } return animal;}

Builder(构造者)

构造者模式主要在于创建一些复杂的对象:

<?php

class Product {

    private $name;

    public function setName($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Builder {

    protected $product;

    final public function getProduct() {
        return $this->product;
    }

    public function buildProduct() {
        $this->product = new Product();
    }
}

class FirstBuilder extends Builder {

    public function buildProduct() {
        parent::buildProduct();
        $this->product->setName('The product of the first builder');
    }
}

class SecondBuilder extends Builder {

    public function buildProduct() {
        parent::buildProduct();
        $this->product->setName('The product of second builder');
    }
}

class Factory {

    private $builder;

    public function __construct(Builder $builder) {
        $this->builder = $builder;
        $this->builder->buildProduct();
    }

    public function getProduct() {
        return $this->builder->getProduct();
    }
}

$firstDirector = new Factory(new FirstBuilder());
$secondDirector = new Factory(new SecondBuilder());

print_r($firstDirector->getProduct()->getName());
// The product of the first builder
print_r($secondDirector->getProduct()->getName());
// The product of second builder

小结:

  每种模式都有自己的优点,选择一种适合自己业务的模式非常重要,能够提高代码的可读性、可维护性等等,希望本文能够对你有所帮助。

 

本文参考电子书《javascript设计模式》

 

使用起来:
Animal *dog = [AnimalHouse animalWithType:AnimalTypeDog];[dog shout];Animal *cat = [AnimalHouse animalWithType:AnimalTypeCat];[cat shout];Animal *sheep = [AnimalHouse animalWithType:AnimalTypeSheep];[sheep shout];

需要注意的是、如果只是将参数赋值给产品(比如颜色等等)、是并不能算作简单工厂模式的。

相比简单工厂、将《工厂》也进行抽象处理。

解决了简单工厂模式下、臃肿的工厂导致增加产品时不宜扩展的弊端。

Structural Patterns

需要以下四个角色:

1.
抽象工厂
与业务方无关、任何在模式中创建对象的工厂必须实现这个接口。2.
具体工厂
实现了抽象工厂接口的具体类、含有与引用密切相关的逻辑、并且受到业务方的调用以创建产品对象。3.
抽象产品
工厂方法所创建产品对象的超类型,也就是产品对象的共同父类或共同拥有的接口。4.具体产品这个角色实现了抽象产品角色所声名的接口。工厂方法所创建的每个具体产品对象都是某个具体产品角色的实例。

Decorator(装饰器模式)

装饰器模式允许我们根据运行时不同的情景动态地为某个对象调用前后添加不同的行为动作。

<?php
class HtmlTemplate {
    // any parent class methods
}

class Template1 extends HtmlTemplate {
    protected $_html;

    public function __construct() {
        $this->_html = "<p>__text__</p>";
    }

    public function set($html) {
        $this->_html = $html;
    }

    public function render() {
        echo $this->_html;
    }
}

class Template2 extends HtmlTemplate {
    protected $_element;

    public function __construct($s) {
        $this->_element = $s;
        $this->set("<h2>" . $this->_html . "</h2>");
    }

    public function __call($name, $args) {
        $this->_element->$name($args[0]);
    }
}

class Template3 extends HtmlTemplate {
    protected $_element;

    public function __construct($s) {
        $this->_element = $s;
        $this->set("<u>" . $this->_html . "</u>");
    }

    public function __call($name, $args) {
        $this->_element->$name($args[0]);
    }
}
以其中一个工厂为例:

与抽象工厂AnimalHouse相比、具体工厂DogHouse隶属于动物园。狗窝里自然全是狗~

//DogHouse+ animal { Animal *animal = [[Dog alloc] init]; return animal;}

Adapter(适配器模式)

这种模式允许使用不同的接口重构某个类,可以允许使用不同的调用方式进行调用:

<?php

class SimpleBook {

    private $author;
    private $title;

    function __construct($author_in, $title_in) {
        $this->author = $author_in;
        $this->title  = $title_in;
    }

    function getAuthor() {
        return $this->author;
    }

    function getTitle() {
        return $this->title;
    }
}

class BookAdapter {

    private $book;

    function __construct(SimpleBook $book_in) {
        $this->book = $book_in;
    }
    function getAuthorAndTitle() {
        return $this->book->getTitle().' by '.$this->book->getAuthor();
    }
}

// Usage
$book = new SimpleBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns");
$bookAdapter = new BookAdapter($book);
echo 'Author and Title: '.$bookAdapter->getAuthorAndTitle();

function echo $line_in) {
  echo $line_in."<br/>";
}
使用起来:
Animal *dog = [DogHouse animal];[dog shout];Animal *cat = [CatHouse animal];[cat shout];Animal *sheep = [SheepHouse animal];[sheep shout];

虽然解决了扩展性。但依旧有个问题、就是当工厂太多、业务需要使用的工厂类型也太多了~

与工厂模式的基本模式相同。最大的区别就是工厂实例不在只生产一种产品、而是生产一个产品族。

Behavioral Patterns

抽象工厂实现:
//AnimalHouse+ (AnimalHouse *)houseWithType:(AnimalType)type { AnimalHouse *house = nil; if (type == AnimalTypeDog) {//狗 house = [[DogHouse alloc] init]; } else if (type == AnimalTypeCat) { house = [[CatHouse alloc] init]; } else if (type == AnimalTypeSheep) { house = [[SheepHouse alloc] init]; } return house;}

Strategy(策略模式)

测试模式主要为了让客户类能够更好地使用某些算法而不需要知道其具体的实现。

<?php

interface OutputInterface {
    public function load();
}

class SerializedArrayOutput implements OutputInterface {
    public function load() {
        return serialize($arrayOfData);
    }
}

class JsonStringOutput implements OutputInterface {
    public function load() {
        return json_encode($arrayOfData);
    }
}

class ArrayOutput implements OutputInterface {
    public function load() {
        return $arrayOfData;
    }
}
具体使用:
//内部生成具体工厂`DogHouse `// AnimalHouse *animalHouse = [AnimalHouse houseWithType:AnimalTypeDog];//或者也可以直接使用具体工厂AnimalHouse *animalHouse = [[DogHouse alloc] init];//内部生成具体产品`MaleDog`MaleAnimal* maleAnimal = [animalHouse maleAnimal];//内部生成具体产品`femaleDog`FemaleAnimal* femaleAnimal = [animalHouse femaleAnimal];//使用该产品[maleAnimal shout];[femaleAnimal shout];

Observer(观察者模式)

某个对象可以被设置为是可观察的,只要通过某种方式允许其他对象注册为观察者。每当被观察的对象改变时,会发送信息给观察者。

<?php

interface Observer {
  function onChanged($sender, $args);
}

interface Observable {
  function addObserver($observer);
}

class CustomerList implements Observable {
  private $_observers = array();

  public function addCustomer($name) {
    foreach($this->_observers as $obs)
      $obs->onChanged($this, $name);
  }

  public function addObserver($observer) {
    $this->_observers []= $observer;
  }
}

class CustomerListLogger implements Observer {
  public function onChanged($sender, $args) {
    echo( "'$args' Customer has been added to the list n" );
  }
}

$ul = new UserList();
$ul->addObserver( new CustomerListLogger() );
$ul->addCustomer( "Jack" );
Cocoa下的应用:

Cocoa框架下使用的为抽象工厂模式、具体使用的对象为NSStringNSArrayNSDictionary以及NSNumber

Chain of responsibility(责任链模式)

这种模式有另一种称呼:控制链模式。它主要由一系列对于某些命令的处理器构成,每个查询会在处理器构成的责任链中传递,在每个交汇点由处理器判断是否需要对它们进行响应与处理。每次的处理程序会在有处理器处理这些请求时暂停。

<?php

interface Command {
    function onCommand($name, $args);
}

class CommandChain {
    private $_commands = array();

    public function addCommand($cmd) {
        $this->_commands[]= $cmd;
    }

    public function runCommand($name, $args) {
        foreach($this->_commands as $cmd) {
            if ($cmd->onCommand($name, $args))
                return;
        }
    }
}

class CustCommand implements Command {
    public function onCommand($name, $args) {
        if ($name != 'addCustomer')
            return false;
        echo("This is CustomerCommand handling 'addCustomer'n");
        return true;
    }
}

class MailCommand implements Command {
    public function onCommand($name, $args) {
        if ($name != 'mail')
            return false;
        echo("This is MailCommand handling 'mail'n");
        return true;
    }
}

$cc = new CommandChain();
$cc->addCommand( new CustCommand());
$cc->addCommand( new MailCommand());
$cc->runCommand('addCustomer', null);
$cc->runCommand('mail', null);
以数组为例:
id obj1 = [NSArray alloc];id obj2 = [NSMutableArray alloc];id obj3 = [obj1 init];id obj4 = [obj2 init];id obj5 = [UIView alloc];id obj6 = [obj5 init];NSLog(@"%@",NSStringFromClass([obj1 class]));NSLog(@"%@",NSStringFromClass([obj2 class]));NSLog(@"%@",NSStringFromClass([obj3 class]));NSLog(@"%@",NSStringFromClass([obj4 class]));NSLog(@"%@",NSStringFromClass([obj5 class]));NSLog(@"%@",NSStringFromClass([obj6 class]));

打印结果:

__NSPlaceholderArray__NSPlaceholderArray__NSArray0__NSArrayMUIViewUIView

可见数组与View不同。alloc生成的对象并不是最终的《产品》、而是一个《工厂》

而且是一个单例工厂:
NSArray * obj1 = [NSArray alloc];NSArray * obj2 = [NSArray alloc];NSMutableArray * obj3 = [NSMutableArray alloc];NSMutableArray * obj4 = [NSMutableArray alloc];NSLog(@"%p",obj1);NSLog(@"%p",obj2);NSLog(@"%p",obj3);NSLog(@"%p",obj4);

输出:

0x6040000103600x6040000103600x6040000103500x604000010350

策略模式

策略模式其实和工厂模式类似、都是利用继承的方式实现。只是《工厂模式更像是对对象的管理》、而《策略模式是对行为的管理》

举个最常见的例子:AFNetworking下的AFHTTPRequestSerializerAFJSONResponseSerializer、二者分别负责编码与解码的策略。

以解码为例、你可以使用不同的策略:AFJSONResponseSerializerAFXMLParserResponseSerializerAFXMLDocumentResponseSerializer等等。将服务器返回的数据解析成不同的结果。

在Cocoa下的应用:

数组排序的:sortedArrayUsingSelector方法。他会依居数组内部不同元素、采用不用元素的排序策略。

装饰模式(Decorator)

是在不改变原封装的前提下,为对象动态添加新功能的模式

主要通过ExtensionCategory来实现

在Cocoa下的应用:

最常用的例子就是NSObjectperformSelector方法集NSObject
(NSThreadPerformAdditions):

- performSelectorInBackground:aSelector withObject:(nullable id)arg;- performSelectorOnMainThread:aSelector withObject:(nullable id)arg waitUntilDone:wait;

@interface NSObject (NSDelayedPerforming):

- performSelector:aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;- performSelector:aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;

适配器模式

将一个类的接口转化为另一个类的接口、使得原本互不兼容的类可以通过接口一起工作

从某些意义上来讲、某些情况下的代理模式也算适配器模式。委托者通过代理要求代理者提供合适的资源。

适配器分为:

  • 类适配器以继承的方式实现、被适配类的子类通过多继承的方式进行格式化输出。
  • 对象适配器存在一个适配器对象、用来将被适配对象进行格式化输出。

实现一个适配器、我们至少需要以下三个对象:1.
被适配者
通常为旧模块2. 适配目标通常为协议接口3.
适配器
类适配器为Adoptee的子类、对象适配器为持有Adoptee的第三者。4.
用户
最终信息的接受者

澳门新浦京电子游戏 2

在Cocoa下的应用:

UITableView作为向UIViewController(Adopter)寻求格式为UITableViewDataSource的资源。而UIViewController(Adopter)、则通过对自身持有的数据源NSArray进行格式化处理后、交付给UITableViewDataSource

Demo的话可以看看《适配器模式的解析-iOS》或者《IOS设计模式浅析之适配器模式》

MVC及一些衍生设计模式

iOS架构补完计划–浅谈MVC及其衍生架构模式

最后

本文主要是自己的学习与总结。如果文内存在纰漏、万望留言斧正。如果不吝赐教小弟更加感谢。

参考资料

IOS设计模式浅析之简单工厂模式(SimpleFactory)iOS
三种工厂模式(简单工厂模式、工厂模式、抽象工厂模式)iOS设计模式之美-抽象工厂模式类簇–抽象工厂模式在OC中的使用iOS策略设计模式适配器模式的解析-iOSIOS设计模式浅析之适配器模式iOS架构师_适配器模式

发表评论

电子邮件地址不会被公开。 必填项已用*标注