首页 新闻 会员 周边

工厂方法模式的疑问

0
悬赏园豆:100 [已解决问题] 解决于 2013-01-11 15:32

参考链接:http://terrylee.cnblogs.com/archive/2006/01/04/310716.html,大致如下:

   public abstract class Log
    {
        public abstract void Write();
    }
    public class EventLog : Log
    {
        public override void Write()
        {
            Console.WriteLine("EventLog Write Success!");
        }
    }
    public class FileLog : Log
    {
        public override void Write()
        {
            Console.WriteLine("FileLog Write Success!");
        }
    }
    //工厂
    public abstract class LogFactory
    {
        public abstract Log Create();
    }
    public class EventFactory : LogFactory
    {
        public override EventLog Create()
        {
            return new EventLog();
        }
    }
    public class FileFactory : LogFactory
    {
        public override FileLog Create()
        {
            return new FileLog();
        }
    }
   //调用
   static void Main(string[] args)
        {
            LogFactory factory = new EventFactory();

            Log log = factory.Create();

            log.Write();
        }

 

上面的调用代码,没有看出工厂方法的好处,如果 没有工厂,也是一样的调用如下:

        static void Main(string[] args)
        {
            //LogFactory factory = new EventFactory();
            Log log = new EventLog();
            log.Write();
        }

再 扩展一个Log的话,又要再写一个实现工厂,再通过实现工厂来创建,是不是多此一举,如果反射的话,直接在配置文件中配置相关log就行,何必用工厂。

各位 都说说,解释一下上面的工厂 或者说说  工厂有什么好处?

Qlin的主页 Qlin | 老鸟四级 | 园豆:2403
提问于:2013-01-09 10:45
< >
分享
最佳答案
0

上面的代码就不看了,我举另外的例子来说明下工厂的好处。假设你写了个类似qq的软件,为了吸引用户用你的软件,只要登录软件就有奖励。最开始你的代码可能是这样的:

void LogOn()
{
       //先做一些验证用户名密码之类的事情
       //登录成功之后要给这个用户奖励了,假设奖励100经验
       user.Exp += 100;          
}

由于运作成功,很多人用,有的人还愿意花钱购买VIP,对于VIP当然要身份尊贵一点,奖励也是不同的,那VIP用户除了奖励200经验,还会奖励1个道具,那么如果为了快速完成功能,代码可能是这样的:(还是在LogOn方法里)

if (user.IsVip)
{
     user.Exp += 200;
     user.Item++;
}
else
{
     User.Exp += 100;
}   

将来会员又有了白金会员,黄金会员,钻石会员等等...于是这个if-else不断扩大,或者是一个庞大的switch-case,已经惨不忍睹了...工厂模式:

void LogOn()
{
      //先登录,下面是发奖励
      BenefitProvider privider = BenefitProvider.Get(user);
      provider.GiveBenefit(user);  //发奖励
}

//BenefitProvider 是一个基类,针对不同的场景返回不同的子类
public abstract class BenefitProvider
{
       public static BeniefitProvider Get(User u)
       {
             //例子中不同的奖励机制取决于user,所以传user进来
             if (!user.IsVip) return new GeneralBenefitProvider();
             else if (!user.IsGoldVip) return new GoldBenefitProvider();
             ....
       }

       public abstract void GiveBenefit(User u);  
       //子类只要把自己的逻辑实现在这个方法里就可以     
}

public class GoldBenefitProvider : BenefitProvider
{
      public override void GiveBenefit(User u)
      {
             //所有金牌vip的奖励逻辑都在这里集中
             u.Exp += 500;
             u.Items += 5;
      }
}

以上代码已经做到了同一业务逻辑集中,不同业务逻辑分离,已经比较好维护了。相信以上代码已经可以体现工厂的优势。事实上它还有更进一步的优化空间,比如工厂的get方法里(BeniefitProvider.Get)依然有很难看的if或者switch。其实如果分支不是非常多的话已经无伤大雅了,因为逻辑很清晰简单了(如果是按照最先的做法if和else之间,或者case之间有大段大段的逻辑,那才是恐怖),要更完美一点可以用IoC容器来作为工厂,这样只要配置好容器就可以了(无论是通过代码配置还是配置文件来配置,殊途同归)。这个你自己去了解吧,否则展开太多了。

收获园豆:20
水牛刀刀 | 大侠五级 |园豆:6350 | 2013-01-09 13:14

谢谢,感觉 只是把代码 进行分离到不同的方法里, 我还是 要再去理解理解

Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 13:26
其他回答(8)
0

你去了解一下设计模式的,工厂模式你就清楚了

也不是说多此一举,要根据项目的实际情况来运用

收获园豆:10
Rich.T | 园豆:3440 (老鸟四级) | 2013-01-09 11:16

谢谢, 我这就是 在了解啊,不清楚的地方来问大家。

能不能 说说,上面的代码 加了 工厂之后,好处 在哪?

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 11:20

@Qlin: 

你上面的这个工厂模式,还没有很大的用处

工厂最大的优势是扩展方便,不需要动主方法,只需要增加扩展类

支持(0) 反对(0) Rich.T | 园豆:3440 (老鸟四级) | 2013-01-09 11:26

@Rich.T: 

1.扩展的话,如果不用工厂,直接扩展一个子类 File1Log,如果使用工厂,而要 多扩展一个  File1LogFactory。

2.Main方法,如果 改了调用方式,也要改成另一个 子工厂。如果不用工厂,要改另一个调用方式,也是改这里,改成new 另一个log。

没看出扩展 哪里方便? 指点一下,谢谢!

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 11:32

@Qlin: 

问题就在这里,你现在是简单工厂,

定义一些配置的话,主方法那里通过接收参数进行调用

支持(0) 反对(0) Rich.T | 园豆:3440 (老鸟四级) | 2013-01-09 11:37

@Rich.T: 

配置一个 具体的子工厂 和 配置一个具体的Log,有什么区别? 一样可以通过反射,请解释一下,谢谢!

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 11:38
0

单纯的调用下new确实还不如用反射+配置文件,但如果里面还有些逻辑,是不是就得用工厂方法了?这里面的逻辑现在没有,或许将来就有了,这不就利于扩展了。

收获园豆:10
向往-SONG | 园豆:4853 (老鸟四级) | 2013-01-09 12:06

谢谢!

有很多 开源项目也用到 工厂方法模式,工厂的逻辑简单,就是创建一个 对象。如果Log里的逻辑变了,子类Log也都的变。 配置文件也可以配置 子类Log。

还是 不太明白 为什么这样做。

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 12:14
0

工厂模式同样遵循开放封闭原则和高内聚低耦合,一般情况下尽可能在工厂模式不要修改,删除,而是添加功能,这就是所谓扩展性。而好处就在于业务逻辑你在工厂实现,ui层代码不管怎么实现,只是调用这个(接口)“黑匣子”。只需要对工厂处理,就是低耦合了。还有一个显著特点就是移植性强。工厂模式做好了,只需改变ui代码,在web,窗体,控制台,甚至net向java移植都会方便好多。

收获园豆:10
伏草惟存 | 园豆:1420 (小虾三级) | 2013-01-09 13:17

谢谢,不是很理解,能 来个具体的例子吗

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 13:29

我学习设计模式是从程杰《大话设计模式》学习的,讲的透彻,程杰博客园网址http://www.cnblogs.com/cj723/category/118146.html。你看看把

支持(0) 反对(0) 伏草惟存 | 园豆:1420 (小虾三级) | 2013-01-09 17:26
0

工厂模式的存在就是要释放new的存在

收获园豆:10
chenping2008 | 园豆:9836 (大侠五级) | 2013-01-09 13:43

new log 和 new 工厂 不是一样吗? 是说 反射 ?

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 13:45

@Qlin: 在反射中还是贡献很大的。

Log log = new EventLog();
写代码的的地方跟这个
EventLog 绑定的很死啊。举个极端的例子,你有10地方
用到了EventLog 这个类,以后要是这个类改名,或者是增加了构造函数(取消了默认的构造函数), 这样的话,你就需要修改10个地方,而用了模式,就需要修改一个地方即可。
支持(0) 反对(0) chenping2008 | 园豆:9836 (大侠五级) | 2013-01-09 14:01

@chenping2008: 

谢谢, 有道理

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 14:26
0

http://www.cnblogs.com/x-xk/archive/2013/01/06/2830742.html

这篇关于工厂的讲的不错,可以看看把思想理解了也就想通了。

收获园豆:10
氤氲鸦 | 园豆:298 (菜鸟二级) | 2013-01-09 14:05

谢谢 去看看

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 14:27
0

设计模式就的主要目的是方便扩展

如果你的程序只有几百行,而且服务的客户只有一家,业务逻辑也很少发生变化,那不用也没关系

收获园豆:10
woaibaojinyuan | 园豆:214 (菜鸟二级) | 2013-01-09 15:37
0

其实就是开闭原则,对扩展开放,对修改封闭!

使用设计模式也是有代价的,就像在你的代码里,如果用工厂模式反会让代码更多,让人感觉“复杂”。。。

但这样的好处是结构清晰,维护方便,一般的小项目压根用不上什么设计模式,只有项目足够大,足够复杂,并且后期会不断完善持续开发,才能体现出设计模式的优势!

收获园豆:10
Alex_QY1987 | 园豆:1888 (小虾三级) | 2013-01-09 16:05

对修改“封闭”到底指的什么呢?是绝对不修改任何代码吗?还是只不用修改客户端的调用代码?

谢谢。

0

你有一个创建水果的工厂,在设计和项目交付给用户使用的时候只考虑了苹果和橘子,但你同时还考虑了会要创建其他的水果,这时候用工厂方法的设计模式去做了这个事情,当用户用了一段时间之后,新的需求是要动态的创建香蕉了,这个时候你只需要再添加一个香蕉的类来,其他的都不用去修改了,你就完成了这个创建的工作,这样说不知你是否理解。

@Alex_QY1987说的就是很正确的

收获园豆:10
az235 | 园豆:8483 (大侠五级) | 2013-01-09 17:49

谢谢,那 看看 我上面的代码,添加一个香蕉,还要 添加一个香蕉的工厂,如果使用香蕉,Main方法还要改成香蕉的工厂来创建。

是否 真的是 不要修改?

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2013-01-09 17:53

@Qlin: 用反射的话,用配置文件就行可以了不用修改原来的代码,开闭原则,对扩展开放,对修改封闭!

支持(0) 反对(0) az235 | 园豆:8483 (大侠五级) | 2013-01-09 18:08

@Qlin: 不要修改是说的,你不用去修改以前写好的算法。。。并不是说你不用修改MAIN函数的意思哦!比如你添加了一个香蕉工厂,再添加一个香蕉的算法,你不用去修改苹果和橘子工厂和算法。

还有Main函数是否需要修改,应该是取决业务需求,跟底层的工厂和算法,并没有太直接的联系呢!

支持(0) 反对(0) Alex_QY1987 | 园豆:1888 (小虾三级) | 2013-01-10 09:55
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册