子墨对酒《三国杀》里论模式(一)工厂模式

有人说模式会让代码变的优雅,也有人说模式会让你的代码更利于扩展。我个人觉得这些说 的都对。但是滥用模式一样会成为被人诟病的痛点。与其说面向对象语言考察的主要标准是语法,不如考察对模式的理解更加切合实际。很大一部分人都觉得模式枯 燥无味,但其实模式是一些充满智慧的集合,可以用在任何的领域,本系列文章就是希望在一种新新的角度里看模式。《三国杀》一 直是我热衷的游戏之一,当然外界对它褒贬不一我们不作深究。我相信很少有人把模式和游戏联系起来,不过我还是愿意开这个先例,如果你觉得我的方式并不赖, 不妨跟我一起探讨,我很愿意和一些志同道合的人聊这些东西,当然不限制于任何的学科。虽然市面上关于模式的文章非常多,但是我还是愿意跟大家老生长谈一 下。这次我们说工厂模式。很多人觉得工厂模式再简单不过了,但是实际上能用的好的人往往很少,而且工厂模式也常常伴随着其他模式出现,这种复合的模式你又 是否能够掌握的很好呢?

很多人认为工厂模式的重点在与构造,但我认为工厂模式重点在于抽象。抽象你的产品比你 创造一个工厂要困难的多。其实工厂模式的存在是控制反转的一种体现。将构造和代码分离,这种实现能有效的分离实现,提高扩展性。比较传统的比喻就是100 个人吃一个产家的面包,当他们打算换一种品牌的时候。采用工厂模式我们只需要变更工厂就行,而不采用控制反转的方式就像是100个人自己去买面包。

当然你一时很难将这两种场景抽象组合起来。那么我们在说工厂模式之前我们不妨先说一下IOC(控制反转)。我们先写一段非控制反转的代码:

Bread a1 = new Bread_味多美();

假如我们买"味多美"的面包,用这种非IOC的写法,假如说我们有一百个类都采用这种写法,相当于100个人都持有这个面包,这时候我们发现”多美“有问题。那怎么办呢?我们只能改这一百个类。所以看出问题了么?~如果面包的种类是多变的那怎么办呢?~这里我们不提工厂,只说IOC,我们将这种控制反转的集合类称为IOC容器。

Bread a = IOC.createBread();

扫描二维码关注公众号,回复: 558086 查看本文章

当我们要换成其他的品牌的时候,我们只需要修改ioc容器一个类的代码即可。不知道这样大家能否跟我一样理会IOC的重要性。好的,如果你已经理解了IOC,我们回头来说一下Factory模式。

工厂主要分成简单工厂,静态工厂,万能工厂,抽象工厂。但实际上如果你理解了IOC的概念,写法这种东西没有什么重要之处,只要你觉得那种写法适合你就行。

所谓简单工厂是工厂最简单的一种写法,但是工厂本身是一个对象。静态工厂与简单工厂相对的,不需要定义工厂对象,而如果从产品种类来说的话,如果你的产品都由同一个工厂产生,那便是万能工厂。抽象工厂是对IOC之上的又一层抽象。对工厂的抽象,可以理解成是工厂的工厂。

为何我要着重讲IOC容器呢?因为很多模式都是充斥着IOC的概念,好吧~我们在三国杀这个游戏里面找找工厂模式的影子吧。


                                                                                                                         我们知道一个三国杀牌局里面有将近100多张的牌,而这些牌的产生我们就可以使用工厂模式:

    Card card = CardFactory.createCrad();

    我们如果只定义牌的元数据的话实际上我们可以得到这样的数据结构:

    class Card{

    String name; //名字

         int imageHandle;//图片句柄

     }      

     当然每一个Card都有一个效果,我们将在以后分析这种效果对象。这里我们继续回到刚才的问题,伟什么要使用工厂模式?或者说为什么要使用IOC呢?

首先,我们所看到的这个界面是不可能一成不变的。假如说我要将“桃”这个对象的某些属 性变更,比如说是图像,或者是名字,字体,说明等等。如果我们用传统new的方式改起来的工作量是非常大的。而你如果采用IOC进行反转的话,你就会发 现,只需要变更你的工厂类就可以了。当然我们这里要抛出来一些问题。一个牌局来说牌数是永远不可能增减的。那么你的牌被回收以后有没有必要重新再new出 来一张新的牌呢?~答案明显是否定的。那么这就引出另外一个模式享元模式。我将在后面跟大家说明一下这个模式,这个模式也是IOC的一种体现,大量的缓冲池代码都用到这种模式。好的我们构造了这些对象我们要对这些卡片附加一些效果。我们展示将这些效果抽象成一个Image魔法对象:

   class Image {

       public abstract void effect();

    }

  class 桃 extends Image{

      public void effect() {

                    +1血; 

     }

 }

我们知道对于桃这种东西来说不论是卡1还是卡2,都是一样的Image效果,那既然这样根本就没有必要对每一个卡片定义专门的效果对象。我们在card对象里面增加一个方法:

class Card{

    public void addEffect(Image...images);

}

我们完全可以定义一个桃对象:

     桃  t = new 桃();

然后将它放到定义好的卡片对象中去:

    Card card1 = new Card(“红桃A”);

    card1.addEffect(t);

    card2 = new Card(“红桃K”);

    card2.addEffect(t);

    card3 = new Card(“红桃6”);

    card3.addEffect(t);

   我们可以看出这种写法不仅节省内存而且要简洁的多。这其实就是聚合模式。我也会在以后的文章中探讨它。当然桃的生成我们就可以采用工厂模式。工厂会封装 好你的对象的生成细节。我可能生成是通过数据库,代码,甚至是云端。我们看到其实三国杀里面用到的很多都是工厂模式的样例。比如英雄对象,按钮对象,牌类 对象,魔法对象,关系对象,文字对象,说明对象,装备对象。这些都是可以通过IOC容器来生成。

   --非子墨

微博账号: 非子墨
QQ:1025250620
CSDN:《非子墨》的空间

猜你喜欢

转载自1025250620.iteye.com/blog/2015105