您的位置:首页 > 其它

工厂模式

2015-09-06 20:48 190 查看

工厂模式

前言

今天开始学习一些常见的设计模式,虽然我写的代码不多,估计设计模式学也学不会,但是没关系,不能因为学不会就不学,好好努力,万事开头难.



今天看了一个老程序员写的建议,给大家分享一下:



不要轻易换笔记本电脑,不要跟潮流,不要买过多的电子产品,不要过于频繁的更换手机.有时候,你可能觉得今天买个耳机,明天买个手机,千儿八百的没啥,但是慢慢地这个洞就越来越大了.







引入

既然是说设计模式的话,还是说点有意思的小东西,主要不想放在代码上,本屌是个注重思想的人,灯泡快坏了,想想这个灯泡也是老式的不如换个新的节能灯泡算了。于是跑到小区对面的德尔泰市场买了同样接口的节能灯泡,这样光线又好又可以为自己节约电费,回来后迅速拿起凳子,换了新灯泡感觉亮堂了许多。想象一下,我们通过一个程序去控制一个电灯的明暗,想象一个这个程序如何实现呢?我想首先第一步就是需要设计当感应设备捕获到人的时候如何处理,第二步就是在处理内部控制灯泡发光,例如声控设备感应到人的时候,控制我们平时的普通灯泡去发光.通过面向对象封装模拟的代码如下:

class Program
    {
        static void Main(string[] args)
        {
            //是否感应到人,默认是
            bool isOpen = true;
            //普通灯泡
            Bulb bulb = new Bulb();
 
            //感应是否生效
            if (isOpen)//默认生效
            {
                //感应器控制灯泡发光
                Induction induction = new Induction();
                induction.Open(bulb); 
            }
        }
    }
    /// <summary>
    /// 感应器
    /// </summary>
    public class Induction
    {
        //打开终端(灯泡)
        public void Open(Bulb bulb)
        {
            //发光
            bulb.Luminescence();
        }
    }
    /// <summary>
    /// 灯泡
    /// </summary>
    public class Bulb
    {
        //发光
        public void Luminescence()
        {
            //灯泡发光的实现
        }
    }


那么这个时候,我又想起了开始我灯泡坏了的事情了,我最后换了一个节能的灯泡,那么我在用代码模拟一个节能灯泡的类吧,代码如下:

/// <summary>
    /// 节能灯泡
    /// </summary>
    public class FrugalBulb
    {
        //节能发光
        public void FrugalLuminescence()
        {
            //节能灯泡发光的实现
        }
    }


那么这个时候我的普通灯泡坏了,为了考虑成本,决定将普通的灯泡换成节能灯泡,那么就会出现一个问题,当普通灯泡的插孔与节能灯泡的插孔不同时?我们需要将灯泡的插孔也换掉,并且感应器也要增加对节能灯泡的调用,这样就大大的加大了替换的成本,不好的替换方法用代码模拟实现如下:

namespace 工厂模式
{
    class Program
    {
        static void Main(string[] args)
        {
            //是否感应到人,默认是
            bool isOpen = true;
            //普通灯泡
            Bulb bulb = new Bulb();
 
            //感应是否生效
            if (isOpen)//默认生效
            {
                //感应器控制灯泡发光
                Induction induction = new Induction();
                induction.Open(bulb);
            }
        }
    }
    /// <summary>
    /// 感应器
    /// </summary>
    public class Induction
    {
        //打开终端(灯泡)
        public void Open(Bulb bulb)
        {
            //发光
            bulb.Luminescence();
        }
        //打开节能终端(灯泡)
        public void OpenFrugal(FrugalBulb fBulb)
        {
            //加入节能发光的调用        
            fBulb.FrugalLuminescence();
        }
    }
    /// <summary>
    /// 灯泡
    /// </summary>
    public class Bulb
    {
        //发光
        public void Luminescence()
        {
            //灯泡发光的实现
        }
    }
 
    public class FrugalBulb
    {
        //节能发光       
        public void FrugalLuminescence()
        {
            //节能灯泡发光的实现      
        }
    }
}


这样的话,实际生活中,我们替换增加了成本,代码模块中我们修改了原先的代码也增加了成本,那么如何降低这些成本呢?







引入工厂

分析了上面的内容,我们可以看出问题有:灯泡实际上都是发光,但是发光的接口不一样.例如:普通灯泡发光调用Luminescence而节能灯泡发光需要调用FrugalLuminescence,如果今后需要替换另一种灯泡则需要进行很大的改动,那么如何解决这个问题呢?就像我们组装电脑一样,主板,CPU,硬盘等等,他们之间都相互遵循了同样的接口.不管是AMD的CPU,还是Inter的CPU,他们之间都用一种同样的公开接口,将来替换CPU就会很方便,其他硬件同样.



那么我们能不能将灯泡也想象成电脑硬件一样,使用统一的接口进行操作呢?当然没问题,分析一下,既然灯泡都是放光,那么我们就可以将灯泡统一一种协议或者约定,即所有灯泡将来都以一种接口呈现,代码如下:

public interface IBulb
    {
        //统一的发光接口
        void Luminescence();
    }


有了约定(接口),那么所有的灯泡都遵循这个约定,我们以后如果需要更换灯泡或者引进新品种灯泡,只需要跟替换电脑配件那样,把就灯泡拔下来将新的插上去,代码如下:

/// <summary>
    /// 灯泡
    /// </summary>
    public class Bulb:IBulb
    {
        //发光
        public void Luminescence()
        {
            //灯泡发光的实现
        }
    }
    /// <summary>
    /// 节能灯泡
    /// </summary>
    public class FrugalBulb:IBulb
    {
        //节能发光       
        public void Luminescence()
        {
            //节能灯泡发光的实现      
        }
    }


这个时候我们再来替换一次灯泡看看,模拟代码如下:



namespace 工厂模式
{
    public interface IBulb
    {
        //统一的发光接口
        void Luminescence();
    }
    class Program
    {
        static void Main(string[] args)
        {
            //是否感应到人,默认是
            bool isOpen = true;
            //普通灯泡
            Bulb bulb = new Bulb();
            //节能灯泡
            FrugalBulb fBulb = new FrugalBulb();
            
            //感应是否生效
            if (isOpen)//默认生效
            {
                //感应器控制灯泡发光
                Induction induction = new Induction();
                //普通灯泡发光
                induction.Open(bulb);
                //节能灯泡发光
                induction.Open(fBulb);
            }
        }
    }
    /// <summary>
    /// 感应器
    /// </summary>
    public class Induction
    {
        //打开终端(灯泡)
        public void Open(IBulb bulb)
        {
            //发光
            bulb.Luminescence();
        }
        //打开节能终端(灯泡)
        public void OpenFrugal(FrugalBulb fBulb)
        {
            //加入节能发光的调用        
            fBulb.Luminescence();
        }
    }
    /// <summary>
    /// 灯泡
    /// </summary>
    public class Bulb:IBulb
    {
        //发光
        public void Luminescence()
        {
            //灯泡发光的实现
        }
    }
    /// <summary>
    /// 节能灯泡
    /// </summary>
    public class FrugalBulb:IBulb
    {
        //节能发光       
        public void Luminescence()
        {
            //节能灯泡发光的实现      
        }
    }
}


这个时候还有一个问题,如果我们将来需要支持彩色灯泡怎么办?我们是不是要增加一个彩色灯泡的类实现灯泡的约定接口,还需要在调用方写入调用的代码.这个时候我们就可以使用工厂类维护这些灯泡,例如:我的灯泡工厂,目前可以制造,普通灯泡,节能灯泡,彩色灯泡.以后我们需要哪一种灯泡,就通知工厂来供货.这样,将来我们需要什么,只需要告诉工厂,工厂给就会给我们提供统一接口的灯泡,供我们使用,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 工厂模式
{
class Program
{
static void Main(string[] args)
{
//是否感应到人,默认是
bool isOpen = true;

//感应是否生效
if (isOpen)//默认生效
{
//感应器控制灯泡发光
Induction induction = new Induction();

//我需要普通灯泡
IBulb bulb = MyBulbFactory.GetBulb("bulb");
//普通灯泡发光

//我需要节能灯泡
IBulb fBulb = MyBulbFactory.GetBulb("fBulb");
//节能灯泡发光
induction.Open(fBulb);

//我需要彩色灯泡
IBulb cBulb = MyBulbFactory.GetBulb("colorbulb");
induction.Open(cBulb);

}
}
}
/// <summary>
/// 感应器
/// </summary>
public class Induction
{
//打开终端(灯泡)
public void Open(IBulb bulb)
{
//发光
bulb.Luminescence();
}
//打开节能终端(灯泡)
public void OpenFrugal(FrugalBulb fBulb)
{
//加入节能发光的调用
fBulb.Luminescence();
}
}
public interface IBulb { //统一的发光接口 void Luminescence(); }

/// <summary> /// 灯泡 /// </summary> public class Bulb:IBulb { //发光 public void Luminescence() { //灯泡发光的实现 } } /// <summary> /// 节能灯泡 /// </summary> public class FrugalBulb:IBulb { //节能发光 public void Luminescence() { //节能灯泡发光的实现 } }
public class ColorBulb : IBulb
{
//彩色灯泡
public void Luminescence()
{
//彩色灯泡发光的实现
}
}

public class MyBulbFactory
{
public static IBulb GetBulb(string bulbName)
{
IBulb bulb = null;

//告诉我你想哪一种灯泡
switch (bulbName)
{
case "bulb":
bulb = new Bulb();
break;
case "frugalbulb":
bulb = new FrugalBulb();
break;
case "colorbulb":
bulb = new ColorBulb();
break;
default:
break;
}
return bulb;
}
}
}


使用工厂模式,可以有效的减少更换同类部件的成本.







抽象类与接口的个人理解

很多人很迷惑什么时候应该使用接口,什么时候使用抽象类呢?



在.NET企业级架构设计一书中,作者对这方面的解释为:”在那些不支持多继承的面向对象语言(例如,java,,C#和VB.NET)中,我们一般倾向于使用接口,因为这样其基类仍有挑选的余地,若支持多继承,则是使用上的偏好了.”



融合了上面的概念之后.我总结的是,当类型之间存在集成关系时,我们使用抽象类,例如一个抽象类人类,那么男人和女人都是人类,他们之间存在着这种派生关系,当类型之间需要遵循一系列约定或者规则时使用接口,例如男人和女人都要学习,工作等等.



也就是说:类型天生的部分封装成抽象类,后天添加的规则方法使用接口,代码实现如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace 抽象类和接口的使用
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
    //学习的约定 规则 行为
 
    public interface ILearn
    {
        void Learn();
    }
 
    //人类是个抽象的类型
    public abstract class Person
    {
        //活动
        public abstract void Activity();
    }
 
    //男人类
    public class Man : Person, ILearn
    {
        //后天的行为
        public void Learn()
        {
            //学习追女人
        }
        //天生的行为
        public override void Activity()
        {
            throw new NotImplementedException();
        }
    }
    //女人类   
    public class Woman : Person, ILearn
    {
        //人类天生的行为       
        public override void Activity()
        {
        }
        //后天的行为       
        public void Learn()
        {
            //学习被男人追       
        }
    }
}


总结

有时候你可能会觉得我想写一个类:
A a = new A();


这样多好啊,又方便又直观,挺好啊,干啥非得写成:

Factory f=new oneFactory();
One one =f.GetOne();


类似这样的工厂模式呢?多此一举?



如果有许多地方都需要生成A的对象,那么你需要写很多
A a=new A();


如果需要修改的话,你要修改很多地方.



但是如果用工厂模式,你只需要修改工厂代码.其他地方引用工厂,可以做到只修改一个地方,其他代码都不动,就是解耦了.



举个例子:如果你有很多地方都需要修改A的实例,那编写一个工厂专门生成A的实例(如果生成逻辑改变了,直接修改工厂).那么这些需要A的实例的地方只需要从工厂中GetObject()就可以了,完全不用管我的实例咋来的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: