• 设计模式之——工厂模式


    几个月之前,我在一家小的软件公司上班。在我来到这家公司的时候,这家公司里面负责C++开发的程序员老L是一个二把刀。原来他是做C#开发的,后来不知道为什么来到这家小公司做C++开发的。我来到公司的第一天就开始了加班的生活,比较累,也很郁闷。做IT的,加班,倒也算可以接受,但是有一点,让很多人会非常的郁闷。那就老L这人为人做事,实在让人有点郁闷。他从不让人修改他写过的代码,这是让我非常郁闷的。为此我和他也吵过,但是死活不相信,坚决不让别人修改他写过的代码。

    我不知道大家在遇到这样的情况该怎么办?也许大家有一些技术上的高招,也许和我一样没技术含量一般和他斗斗嘴,然后偷偷改几个必须修改的类。但是事情过去了两个月左右了,当我再次回忆此次事情的时候,我终于觉得还是自己技术太菜。如果要是我的技术更高一点,或许摩擦会少一点。特别是我开始阅读设计模式这些书之后,再来回顾那些曾经老人们说过的话,写代码要“高内聚,低耦合”。心里自然会明亮了很多,感叹老人们的技术的厉害。好的代码,能够减少两个程序员之间很多的矛盾。

    言归正传。对于工厂模式,之前看了一点,囫囵吞枣。终于决定再次看一遍,虽挑灯夜战,但是也觉得很幸福。人只有在经历过磨难,才觉得普通的生活就是幸福。所以再次劝大家看书,务必要细心。浮躁的人成不了大事。

    工厂模式分为普通工厂模式和抽象工厂模式。相比于普通工厂模式,抽象工厂模式能够做到更加的低耦合。下面我的例子是模仿大话设计模式里面的例子。

    学雷锋做好事:

    我们现在有一个雷锋类,雷锋类里面有一个成员函数做好事(函数)。

    class Leifeng
    {
    public:
    	Leifeng(){cout<<"<Leifeng>"<<endl;}
    	virtual ~Leifeng(){cout<<"<~Leifeng>"<<endl;}
    
    public:
    	virtual void DoGoodThing() = 0;
    };
    

     当然,雷锋做好事,全中国只有一个雷锋,不能全指望雷锋做好事。咱们也得动动手,学雷锋做好事。于是全国各个不同年级的学生都开始学做好事,小学生,中学生,高中生,大学生,都不甘落后学雷锋做好事。于是乎我们就需要从雷锋继承做好事的精神,动手做好事。

    创建小学生学雷锋做好事的类

    class CXiaoxuesheng: public Leifeng
    {
    public:
    	CXiaoxuesheng()
    	{
    		cout<<"<CXiaoxuesheng>"<<endl;
    	}
    	~CXiaoxuesheng()
    	{
    		cout<<"<~CXiaoxuesheng>"<<endl;
    	}
    public:
    	virtual void DoGoodThing()
    	{
    		cout<<"小学生,帮老太太扫地"<<endl;
    	}
    };
    

    创建中学生学雷锋做好事的类

    class CZhongxuesheng: public Leifeng
    {
    public:
    	virtual void DoGoodThing()
    	{
    		cout<<"中学生,帮老太太擦玻璃"<<endl;
    	}
    };
    

    创建高中生学雷锋做好事的类

    class CGaozhongsheng: public Leifeng
    {
    public:
    	virtual void DoGoodThing()
    	{
    		cout<<"高中生,帮老太太买米"<<endl;
    	}
    };
    

    创建大学生学雷锋做好事的类

    class CDaxuesheng: public Leifeng
    {
    public:
    	virtual void DoGoodThing()
    	{
    		cout<<"大学生,给老太太看病"<<endl;
    	}
    };
    

    这个时候,我们可以根据不同的学生类型来产生不同的学生对象。我们需要有一个工厂类。(具体为什么这样做,先看完了全文,然后自然会明白的)

    创建一个工厂类

    class CFactory
    {
    public:
    	virtual ~CFactory(){}
    
    public:
    	static Leifeng *GetHaoren(char ch)//x,z,g,d分别表示小学生,中学生,高中生,大学生
    	{
    		switch(ch)
    		{
    		case 'x': return new CXiaoxuesheng();
    		case 'z': return new CZhongxuesheng();
    		case 'g': return new CGaozhongsheng();
    		case 'd': return new CDaxuesheng();
    		default: return NULL;
    		}
    	}
    };
    

     在主函数里面我们现在可以完成调用工厂模式调用过程:

    Leifeng *pLeifeng = CFactory::GetHaoren('x');//
    pLeifeng->DoGoodThing();
    

     以上就是一个完整的工厂模式的设计。可以对照下面的图片理解一下:

    工厂模式,说白了就是一个带有虚函数的类A(通常是纯需函数),再根据不同的情况,对该类进行派生,形成多个派生类A1,A2,A3,...,An。另外一个就是工厂类Factory,这个Factory有一个成员函数,专门根据不同的情况产生派生类An对象,并且将派生类对象的指针返回。我们定义一个类A的指针,把之前返回的值,赋值非类A的指针。这个时候,我们就可以调用类A的成员虚函数(这个时候,就调用的是派生类中虚函数的实现过程)。

    抽象工厂模式:

    抽象工厂模式,就是将工厂类再次进行抽象。

    这样,我们的工厂类仅仅申明可以建立不同的做好事人员对象,并不做什么实际工作。

    class CFactory
    {
    public:
    	CFactory(){}
    	virtual ~CFactory(){}
    public:
    	virtual Leifeng *GetHaoren() = 0;
    };
    

    这个时候,我们需要根据实际的情况来看,我们有小学生做好事,中学生做好事,高中生做好事,大学生做好事。因此我们需要对他们进行实例化。

    class CXiaoxueshengFactory:public CFactory
    {
    public:
    	virtual Leifeng *GetHaoren()
    	{
    		return new CXiaoxuesheng();
    	}
    };
    
    class CZhongxueshengFactory: public CFactory
    {
    public:
    	virtual Leifeng* GetHaoren()
    	{
    		return new CZhongxuesheng();
    	}
    };
    class CGaozhongshengFactory:public CFactory
    {
    public:
    	virtual Leifeng* GetHaoren()
    	{
    		return new CGaozhongsheng();
    	}
    };
    class CDaxueshengFactory:public CFactory
    {
    public:
    	virtual Leifeng * GetHaoren()
    	{
    		return new CDaxuesheng();
    	}
    };
    

     此时我们可以在调用的时候,就可以有如下操作:

    int main()
    {
    	CFactory * pFactory = new CXiaoxueshengFactory();
    	Leifeng * pLeifeng = pFactory->GetHaoren();
    	pLeifeng->DoGoodThing();
    	delete pLeifeng;
    	return 0;
    }
    

     以上就是学雷锋做好事抽象工厂模式,下面是完整的代码。

    #include <iostream>
    using namespace std;
    
    class Leifeng
    {
    public:
    	Leifeng(){cout<<"<Leifeng>"<<endl;}
    	virtual ~Leifeng(){cout<<"<~Leifeng>"<<endl;}
    
    public:
    	virtual void DoGoodThing() = 0;
    };
    
    class CXiaoxuesheng: public Leifeng
    {
    public:
    	CXiaoxuesheng()
    	{
    		cout<<"<CXiaoxuesheng>"<<endl;
    	}
    	~CXiaoxuesheng()
    	{
    		cout<<"<~CXiaoxuesheng>"<<endl;
    	}
    public:
    	virtual void DoGoodThing()
    	{
    		cout<<"小学生,帮老太太扫地"<<endl;
    	}
    };
    
    class CZhongxuesheng: public Leifeng
    {
    public:
    	virtual void DoGoodThing()
    	{
    		cout<<"中学生,帮老太太擦玻璃"<<endl;
    	}
    };
    
    class CGaozhongsheng: public Leifeng
    {
    public:
    	virtual void DoGoodThing()
    	{
    		cout<<"高中生,帮老太太买米"<<endl;
    	}
    };
    
    class CDaxuesheng: public Leifeng
    {
    public:
    	virtual void DoGoodThing()
    	{
    		cout<<"大学生,给老太太看病"<<endl;
    	}
    };
    
    class CFactory
    {
    public:
    	CFactory(){}
    	virtual ~CFactory(){}
    public:
    	virtual Leifeng *GetHaoren() = 0;
    };
    
    class CXiaoxueshengFactory:public CFactory
    {
    public:
    	virtual Leifeng *GetHaoren()
    	{
    		return new CXiaoxuesheng();
    	}
    };
    
    class CZhongxueshengFactory: public CFactory
    {
    public:
    	virtual Leifeng* GetHaoren()
    	{
    		return new CZhongxuesheng();
    	}
    };
    class CGaozhongshengFactory:public CFactory
    {
    public:
    	virtual Leifeng* GetHaoren()
    	{
    		return new CGaozhongsheng();
    	}
    };
    class CDaxueshengFactory:public CFactory
    {
    public:
    	virtual Leifeng * GetHaoren()
    	{
    		return new CDaxuesheng();
    	}
    };
    
    int main()
    {
    	CFactory * pFactory = new CXiaoxueshengFactory();
    	Leifeng * pLeifeng = pFactory->GetHaoren();
    	pLeifeng->DoGoodThing();
    	delete pLeifeng;
    	return 0;
    }
    

    最后,我们回过头来在看代码,我们在main函数中,只需要改动new后面的CXiaoxueshengFactory类类型,就可以产生不同的对象(比如中学生,大学生等),这个时候就可以让别的学生做其他的好事。如果我们在做好事的人里面,添加社会义工这一项,那么我们只需要继续从leifeng这个类中继承一下。然后再工厂类中继承一下,产生新类,用于生成义工这一个类对象。 我们完全不需要修改原来别人的代码,就能够完成添加不同的学雷锋群体,以及他们具体做什么好事。

    再回头想想我的同事老L不让我修改他的代码。假设他当时能够写成这样的代码,我和他之间就没有任何的冲突可产生。还是自己的能力太弱了。呵呵

  • 相关阅读:
    MySQL性能优化的最佳经验
    18个网站SEO建议
    sql之left join、right join、inner join的区别
    PHP与MYSQL事务处理
    Firefox上Web开发工具库一览
    SphinxSE的安装
    python XML
    python yaml
    C语言文本处理
    Linux strace命令
  • 原文地址:https://www.cnblogs.com/BreakMind/p/2433999.html
Copyright © 2020-2023  润新知