zoukankan      html  css  js  c++  java
  • 生成对象的模式(PHP)

    天气:昨天刚下完小雪  心情:misslsy

    学习一门语言很简单,但不仅仅是语法会了,就可以“为所欲为”了。PHP(或Java)的面向对象中,那些名词比如继承,多态等等,也不算难理解。可是,拿起一本书,里面谈的都是些它娘的模式,看着就有一种浅浅的睡意。

    正题是生成对象的模式(应该可以叫方法)。也许模式的诞生就是为了让代码更优雅些,比如让它灵活些,执行效率高一些(想当然)。
    单例模式,单例也就是说只能有一个。换句话说,只能生成一回,之后随便用(这可以理解成全局变量)。这样,可以在代码任何处调用这个“全局”对象。这是咋实现的呢...

    class SingleObject{
    private static $instance;
    
    private __construct(){;}
    
    public static function getInstance(){
    if(empty(self::instance)){
    self::instance = new SingleObject();
    }
    return self::instance;
    }
    
    //other function methods...
    }
    
    $so = SingleObjecj::getInstance();

    由于构造方法是私有的,所以无法在类外部直接实例化。可以通过类中的静态方法getInstance()来取得对象。由于getInstance()是类内部的方法,所以生成对象时没有问题的。在调用getInstance(),会进行条件判断,以保证只生成一会对象(单例)。
    然而,它又有什么优点呢。书上说“适当使用单例模式可以改进系统的设计......单例模式是一种全局变量的改进。你无法用错误类型的数据复写一个单例。这种保护在不支持命名空间的PHP版本里尤其重要。”哎~,我在叹气...
    下一战模式,也许你听说过。工厂方法模式。
    面向对象是一种思想,也许你听说过“抽象类高于实现”,还有一句“为接口并非实现编程”。我想它是在说,面向对象要把重点放在一层一层的关系上,然后逐层的实现每一层的功能(即责任)。当然,也许不是一层一层的关系,也可能是组合的关系(一个类持有一个或多个其他类的对象的情况)。
    我们假设一个工厂负责生产iOrange(橘子手机,嘎嘎)手机,有销往中国和美国两种。那么我们先写一个Manager(即创建者/creater),再写一个SaleCountry(产品/product)。

    abstract class SaleCountry{
    abstract function country();
    }
    
    class ChinaSaleCountry extends SaleCountry{
    function country(){
    //...
    }
    }
    
    class AmericaSaleCountry extends SaleCountry{
    function country(){
    //...
    }
    }
    
    class Manager{
    function getIorange(){
    return new ChinaSaleCountry(); 
    }
    }

    我们此时只能通过Manager类生成销往中国的iOrange手机,如果想得到美国的,只要稍微改动一下Manager,很快的就会实现。

    class Manager{
    const CHINA = 1;
    const AMERICA = 2;
    private $mode = 1;
    
    function __construct($mode)
    {
    $this->mode = $mode;
    }
    
    function getIorange($this->mode){
    switch($this->mode){
    case(self::CHINA):return ChinaSaleCountry(); 
    case(self::AMERICA):return AmericaSaleCountry();
    default:return null;
    }
    }
    }
    
    $phone = new Manager(Manager::CHINA);//得到中国橘子手机
    $phone = new Manager(Manager::AMERICA);//得到美国橘子手机

    如果老板
    很不错,如果这个厂家的老板想为每个手机制造一份说明书(instruction),同样有中国和美国两种。我们需要在创建类(Manager)中添加一个方法getInstruction()。这个方法会写成这样...

    function getInstruction($this->mode){
    switch($this->mode){
    case(self::CHINA):return "China iBanana instruction"; 
    case(self::AMERICA):return "America iBanana instruction";
    default:return null;
    }
    }

    这时类方法中出现了重复的条件语句(switch判断结构),这不容乐观(如果许多类似get...的方法在Manager中出现,代码冗余现象就会出现了)。
    所以,这时我们将Manager(创建者)定义成抽象类,并创建两子创建者类(分别管理销售到中国和美国的创建者)。这就是工厂方法模式。书上写到“工厂方法模式吧创建者类与主要生产的产品类分离开来。创建者是一个工厂类,其中定义了用于生成产品对象的类方法。如果没有提供默认实现,那么就由创建者子类来执行实例化。一般情况下,就是每个创建者类的子类实例化一个相应产品子类。”好了,看代码如何做...

    abstract class SaleCountry{
    abstract function country();
    }
    
    class ChinaSaleCountry extends SaleCountry{
    function country(){
    //...
    }
    }
    
    class AmericaSaleCountry extends SaleCountry{
    function country(){
    //...
    }
    }
    
    class Manager{
    abstract function getInstruction();
    abstract function getIorange();
    }
    
    class ChinaManager extends Manager{
    function function getInstruction(){
    return "China iBanana instruction";
    }
    
    function getIorange(){
    return ChinaSaleCountry(); 
    }
    }
    
    
    class AmericaManager extends Manager{
    function function getInstruction(){
    return "America iBanana instruction";
    }
    
    function getIorange(){
    return AmericaSaleCountry();
    }
    }

    接下来是抽象工厂模式,继续说上面生产手机的例子。如果,我们继续添加销往日本、法国、英国等类型的手机,这时我们要创建若干个子创建者(JapanManager...),这时使代码结构“横向”增长。如果,我们要为手机添加一些属性,比如上文提到的说明书(因为不同国家的语言有区别),或者网络服务商(比如中国的移动、联通)等,这时就属于纵向增长(对不起,这个例子举得不当,因为纵线增长的属性应该是能用不同国家区别的,在这里有些勉强)。这种纵向增长的例子,就属于抽象工厂模式。

    abstract class SaleCountry{
    abstract function country();
    }
    
    class ChinaSaleCountry extends SaleCountry{
    function country(){
    //...
    }
    }
    
    class AmericaSaleCountry extends SaleCountry{
    function country(){
    //...
    }
    }
    
    abstract class ServerCountry{
    abstract function country();
    }
    
    class ChinaServerCountry extends ServerCountry{
    function country(){
    //...
    }
    }
    
    class AmericaServerCountry extends ServerCountry{
    function country(){
    //...
    }
    }
    
    class Manager{
    abstract function getInstruction();
    abstract function getIorange();
    }
    
    class ChinaManager extends Manager{
    function function getInstruction(){
    return "China iBanana instruction";
    }
    
    function getIorange(){
    return new ChinaSaleCountry(); 
    }
    
    function getServer(){
    return new ChinaServerCountry()
    }
    }
    
    
    class AmericaManager extends Manager{
    function function getInstruction(){
    return "America iBanana instruction";
    }
    
    function getIorange(){
    return new AmericaSaleCountry();
    }
    
    function getServer(){
    return new AmericaServerCountry()
    }
    }

    工厂方法模式和抽象工厂模式的结合“将系统与实现的细节分离开来”,我们可以在实例中添加或删除任意一个销往的国家类型二不会影响系统。
    其次,“对系统中功能相关的元素强制进行组合”。因此,通过使用ChinaManager,可以确保只使用China相关的类。
    但是,添加新的销往国家的类别会很繁琐。“因为不仅要创建新产品的具体实现,而且为了支持它,我们必须修改抽象创建者和它的每一个实现”。(其中用引号括起来的内容均在这书中的内容,下同。)
    最后一种模式,原型模式(抽象工厂模式的变形)。在这种模式下,”创建一个保存具体产品的工厂类,并在初始化时就加入这种做法...这样做可以减少累的数量”。(其实,就是在工厂类中的构造方法中设置参数,以此为根据来生产相应的产品)书中的例子...

    class Sea{}
    class EarthSea extends Sea{}
    class MarsSea extends Sea{}
    class Plains{}
    class EarthPlains extends Plains{}
    class MarsPlains extends Plains{}
    class Forest{}
    class EarthForest extends Forest{}
    class MarsForest extends Forest{}
    
    class TerrainFactory{
    private $sea;
    private $forest;
    private $plains;
    
    function __construct(Sea $sea,Plain $plains,Forest $forest){ 
    $this.sea = $sea;
    $this.plains = plains;
    $this.forest = forest;
    }
    //other functions...
    }

    如果你想在有火星的森林、地球的海洋以及火星的平原上的星球上作战,那么就可以用这句代码:
    $factory = new TerrainFactory(new MarsForest(),new EarthSea(),new MarsPlains());(为什么说是战斗呢,因为这是个游戏呀^^)。
    到这吧,头晕目眩的,慢慢理解。

  • 相关阅读:
    numpy—————数组操作
    ML———聚类算法之K-Means
    DataFrame————数据离散化处理(元素定位与离散化处理)
    windows 搭建和配置 hadoop + 踩过的坑
    Pandas -----简述 Series和DataFrame
    numpy 函数和用法总结、示例
    分词————jieba分词(Python)
    (31)本地yum仓库的安装配置
    (30)zookeeper的数据结构
    (29)zookeeper的命令行客户端
  • 原文地址:https://www.cnblogs.com/wuniaoheart/p/2877224.html
Copyright © 2011-2022 走看看