• as3设计模式乱用之工厂模式


    好久没写技术相关的日记了,一忙,二懒,三则被这单调的生活熏得没什么感悟。

    其实这篇日记早就想写了,项目开发初期的时候,带学生。经常看到那种乱用设计模式的现象。一方面,公司面试人的时候喜欢问设计模式,另一方向设计模式相关的书夸大了设计模式。紧接着的就是一群刚入行的人盲目的崇拜和乱用,感觉用了设计模式就牛逼,用了就脱离菜鸟群体。

    好吧,今天蛋痛。先声明,这篇文字纯个人感觉写,我不是博士也不是研究生,不保证观点全正确。

    我用一个简单的程序员说法,工厂模式是一个类里面有个工厂,工厂通过switch把字符串转成新建的子对象。
    as代码大概如下:

    class factory
    {
    public function createItem(itemName:String):ItemBase
    {
    switch(itemName)
    {
    case...
    }
    
    }
    

      

    详细的那几个类的网上随便搜,我就不粘贴了。

    我想说的是这个模式给我们开发带来的好处有哪些。读过两本关卡设计模式的书,不知是巧合还是不负责的抄袭。两本书为说明工厂的好处都举了个打印机的例子。
    按书上说,用工厂的好处是隐藏产品类。如果我需要创建一台打印机,我只需要创建工厂就行。其实这个说法非常别扭,换个说法我只需要打印,我干麻要非要多余找个工厂。尽信书不如无书啊,这摆明就是google翻译忽悠买书人啊。
    o'reilly的书(as设计模式)还举了个飞机和子弹的例子。当年刚开始看的时候,是和两个刚出社会的同事一起的。有人表示,很灵活啊,我要创建子弹就从工厂里面创建。其实我那时就很纳闷,我直接new一个子弹就得了。搞个子弹基类,还得建立工厂,建好了还要从工厂里面通过字符串创建。码量多了好多,其结果就是出个子弹而已。这个飞机子弹的例子,我们加个另一个前提就更容易理解了,因为前后端交互,服务端给客户端的是字符串或者是整型,客户端要通过这个字符串转换成子弹显示在场景。如此就不得不用上工厂模式。不过话说回来,既然是不得不用,那书就算不看我们也一样是这样写代码,而看了书的人大多只会用switch。不看的还会用反射和映射。
    谈到了这里我想起不只一次听过的话,"用模式,性能会下降些"。其实这句话是有问题的,很多情况下我们是不得不用模式。就如上面说的服务端字段转子弹的例子。所以跟本不存在用会下降不用提升的说法。硬要说会造成性能浪费的话,只能说是乱用,见下例。


    这是个奇怪的例子,这串代码是要创建一个按钮显示到界面上。我读旧项目经常碰到这种写法,毕竟一个项目经过的人手多,什么风格都有。

    var btn:RedButton = BtnFactory.createBtn(BtnName.RED) as RedButton;
    

      


    开发者本来只需要一个红色的按钮,但是却弄了个工厂,在工厂里面通过switch来创建。这样做有什么好处?干麻不直接btn = new RedButton();我只能说,死读书害死人。上例这种写法我们也不能说他有错,但是不得不说,浪费这么多代码没换来什么好处。
    如果说我们希望一个xml来配置显示产生不同的按钮,那工厂写法是有用的,因为配置文件全是字符串,我们需要字符串来创建不同的按钮。但是自己写的一个项目,并无任何配置的东西,这样硬生生加个工厂不就变成了浪费体力了吗。


    搜了很多国外的资料,老外关于as3用是否合适用设计模式进行了不少口水战。而到了国内,就变成了尽信模式,省下了口水。首先我先表明一下自己的关点,本人认为如果追求快速开发,并且对代码严谨性没有强迫证的话,as3的很多设计模式都可以用反射替代。
    说起反射这个词,是从java那学来的,详细的作用是通过类的字符串创建实例。在as里面实现比java简单得多。例如:

    public function getBut(btnName:String="Button"):Button
    {
    var cls:Class = applicationDomain.getDefinition("Button") as Class;
    return new cls();
    }
    

      


    这个写法也很简单和工厂一样,通过一个字符串来创建子项产品。但是为什么书上不说用反射工厂,却要搞好几个类来连接呢?其实这也是有原因的,因为早年,java刚开始的那几个版本是没有反射这个东西的。别说早年的java,现在的C要实现反射也是件麻烦的事。

    举个常用的例子,例如我们要写个列表组件List。列表通过循环创建有子项,每个子项从上到下按Y抽进行排列。我写好了列表之后,给其他人用,别人当然就不希望再重新写一次子项创建和Y排列啦,但是他们要显示的子项是不一样的。相信开发过一个项目的人都知道,在列表里面用一个Class类型的变量存子项类型,循环创建子项可通过这个变量来创建子项。
    大致代码如下:

    var ls:List = new List();
    ls.itemClass = OtherItem;
    ls.data = [11,22,33];
    

      

    在这里我提个假设,如果不用Class变量来反射的话,(也就是不准用Class类型的变量)。别人要用你写的List类,但又要产生不同的子项,要怎么办?
    这种情况下我们可以写一个protected方法来创建子项,别人用的时候就新建一个List2和一个自己的MyItem,继承于List,然后覆盖掉那个protected方法来返回新子项MyItem。这个方法比较简单就不上码了,至于叫什么模式我不记得了,毕竟不是搞学术,唉。
    还有另一种方法就是搞模式的人最喜欢用的,定一个工厂方法接口IItemFactory,这个接口有一个创建子项的方法,List里定一个接口变量。别人扩展的时候新建一个子项工厂接入那个IItemFactory,然后实现那个方法返回一个新的MyItem。(写完这段,发现自己表述水平真有限,算了,上码吧)。

    //IItemFactory代码
    class IItemFactory
    {
    function createItem():ItemBase;
    }
    
    //ItemFactory代码:
    class ItemFactory implements IItemFactory
    {
    public function createItem():ItemBase
    {
    return new MyItem();
    }
    }
    
    
    //List部份代码:
    class List
    {
    ...
    public var itemFactory:IItemFactory;
    
    for (var i:int = 0; i < data.length; i++) 
    {
    var itm:ItemBase = itemFactory.createItem();
    ...
    addChild(itm);
    }
    }
    //使用代码
    var ls:List = new List();
    var itmf:IItemFactory = new ItemFactory();
    ls.itemFactory = itmf;
    ls.data = [11,22,33];
    ...
    

      


    怎么样,很复杂吧。这就是命贱不用反射,硬生生要用工厂的后果。呵呵~~

    这两个例子算是把反射替代工厂好处说完了吧。下面想说一下严谨性这个东西。虽然我目前是搞as3的,但说句实话,as3的语法确实不如java严谨,java有一个叫做泛型的东西,泛型用得好的话,项目在编译之前就几乎把bug找完了。as3的Vector硬搬了泛型这个概念,相比全抄这概念的C#算是弱暴了。
    举个例子,List中的itemClass属性能赋值任何类型,如果赋值对象不是显示对象的话,我们只有在项目运行的时候,调整这个List才能知道这个赋值有问题。java的泛型解决了这点,直接来个Class<DisplayObject>这样的变量,如果赋值的不是显示对象,那在项目编译之前就会报错了。
    as3没有严格的泛型,所以有严谨性强迫证的同学,就宁愿弃反射而用工厂。因为工厂方法也是可以在编译之前报错的。详细的我就说不了太多,自己也不知道自己是否研究的到可以吹的程度。

    C语言是没有反射,java是早期的版本没有反射(本人研究不算深,纯属听说)。Adobe在设计as的时候很多高级语言里复杂的东西都被简化了,我们干麻还非要走回高级语言那个套路呢。
    as3的Object已经包含有了HashMap的功能,但有些人还是硬生生的又搞一个HashMap类。里面又是一堆看着蛋疼的代码。算了,扯远了,就写这么多。下次有空再扯一下设计模式之接口乱用。以博主懒散的更新的速度,不知道是哪个朝代咯。

  • 相关阅读:
    单工、半双工和双工通信
    Callable和Future
    有状态和无状态服务
    paxos协议
    OOP面向对象编程的三大特性
    php工厂模式
    php 观察者模式
    php的单例模式
    php是单继承还是多继承呢?
    MySQL—内连接join 和外连接 left join 区别 交叉连接 a,b cross joni union 联合
  • 原文地址:https://www.cnblogs.com/pelephone/p/as3-factory-design.html
Copyright © 2020-2023  润新知