简单工厂模式,工厂方法模式,抽象工厂模式,spring的狂想

      菜鸟D在项目中遇见一个比较纠结的高耦合,所以就想办法来解耦。情况是这样的:系统通过用户选择treeview控件的节点判断调用不同的处理,这些处理中某些东西又是类似的。同事的建议是采用简单工厂,耦合就耦合吧,反正treeview节点基本是不会变化的。(能偷懒就偷懒吧)

      菜鸟D有些偏执,想找些方法来解耦。于是就学习了这个几种方法,虽然不一定用的上,多学一点总是好的。

      首先说简单工厂,例子是一个已经二到死的计算器。

      简单工厂由三种角色组成:工厂类角色(creator),抽象产品类角色(product,图中为Iproduct接口),具体产品类角色(concreteproduct,图中为Product_A…)。

    代码如下:

public class Calculate{public double DValue1 { get; set; }public double DValue2 { get; set; }public virtual double GetResult(){return 0;}}public class Add : Calculate{public override double GetResult(){return DValue1 + DValue2;}}public class Sub : Calculate{public override double GetResult(){return DValue1 - DValue2;}}public class Mul : Calculate{public override double GetResult(){return DValue1 * DValue2;}}public class Div : Calculate{public override double GetResult(){if (DValue2.Equals(0)){if (DValue1.Equals(0)){return 1;}return 0;}return DValue1 / DValue2;}}
基本的代码
            #region 客户端Console.WriteLine("请输入第一个数");string v1 = Console.ReadLine();Console.WriteLine("请输入运算符");string oper = Console.ReadLine();Console.WriteLine("请输入第二个数");string v2 = Console.ReadLine();Calculate c = GetCalculateByOper(oper);c.DValue1 = Convert.ToDouble(v1);c.DValue2 = Convert.ToDouble(v2);Console.WriteLine("结果:" + c.GetResult()); #endregion#region 工厂方法private static Calculate GetCalculateByOper(string oper){Calculate c = new Calculate();switch (oper){case "+": c = new Add();break;case "-": c = new Sub();break;case "*": c = new Mul();break;case "/": c = new Div();break;}return c;} #endregion    

      在这个例子中没有使用抽象类,接口,而是用了虚方法(纯粹是不想在接口里定义属性,自己喜欢用什么就用什么,毕竟这不是简单工厂的核心)。简单工厂的核心是充当工厂类角色的工厂方法(起码在此例中是这样),逻辑判断中使具体产品类和工厂直接耦合了(好像类图的关系已经决定了这种耦合,但是将具体产品和客户端解耦)。如果要添加一个开方运算,首先添加开方的运算类,然后打开工厂方法进行修改。(呵呵,违反了开闭原则)

     接下来再说一下工厂方法模式,类图如下:

      先分析一下类图,工厂模式有了四个角色:工厂接口,工厂实现,产品接口,产品实现(其实说角色不贴切,还不如说是种类)。工厂实现和产品实现有了依赖关系,通过调用工厂实现来获取产品实现。也就是一种产品实现对应一种工厂实现。

     还是那个二的要死的计算器的例子,代码如下:

    public interface IFactory{ICalculatable GetCalculatable();}public interface ICalculatable{double GetReslut(double d1, double d2);}public class Add : ICalculatable{public double GetReslut(double d1, double d2){return d1 + d2;}}public class AddFactory : IFactory{public ICalculatable GetCalculatable(){return new Add();}}public class Sub : ICalculatable{public double GetReslut(double d1, double d2){return d1 - d2;}}public class SubFactory : IFactory{public ICalculatable GetCalculatable(){return new Sub();}}public class Mul : ICalculatable{public double GetReslut(double d1, double d2){return d1 * d2;}}public class MulFactory : IFactory{public ICalculatable GetCalculatable(){return new Mul();}}public class Div : ICalculatable{public double GetReslut(double d1, double d2){if (d2.Equals(0)){if (d1.Equals(0)){return 1;}return 0;}return d1 / d2;}}public class DivFactory : IFactory{public ICalculatable GetCalculatable(){return new Div();}}
基本代码
#region 逻辑判断public class Factory{public static IFactory GetCalculatableByOper(string oper){IFactory factory = null;switch (oper){case "+": factory = new AddFactory();break;case "-": factory = new SubFactory();break;case "*": factory = new MulFactory();break;case "/": factory = new DivFactory();break;}return factory == null ? null : factory;}} 
#endregion#region 客户端Console.WriteLine("请输入第一个数");string v1 = Console.ReadLine();Console.WriteLine("请输入运算符");string oper = Console.ReadLine();Console.WriteLine("请输入第二个数");string v2 = Console.ReadLine();ICalculatable calculatable = Factory.GetCalculatableByOper(oper).GetCalculatable();Console.WriteLine("结果:" + calculatable.GetReslut(Convert.ToDouble(v1), Convert.ToDouble(v2))); #endregion

      注意:此处的判断逻辑已经不属于工厂模式了(类图中很明确),也可以脱离客户端。虽说简单工厂也可以这样将判断逻辑脱离客户端,但是简单工厂的逻辑判断是在工厂类中的,也就依然是简单工厂模式的一部分(此处逻辑有些乱,不懂的就认真研究类图)。通常在工厂模式的客户端需要用到哪种工厂再去创建哪种工厂,而不是如例子中的使用一个判断逻辑来选择,也就是工厂模式创建工厂是通过“外部”的逻辑来确定,而模式本身是不会做判断的。(所以这个例子并不是一个合适的例子)

      此时,计算器要再添加一个开方的方法,只需添加方法实现,添加工厂实现,不会对原有的代码做修改,符合了开闭原则(你当我瞎啊,你不修改判断逻辑吗?说了多少次了,判断逻辑部分不属于工厂模式。不过比简单工厂确实多写不少东西)。

      工厂方法模式通常在以下两种情况中使用 :

      第一,需要使用某种产品,客户端很清楚应该使用哪个具体工厂,此种情况不存在上述的判断逻辑,只需要实例化具体工厂,然后生产具体产品。

      第二,需要使用某种产品,但是不想也不需要知道是哪个工厂创建,此种情况存在一定的判断逻辑,但是客户端不需要知道这个逻辑,生产方(工厂模式)是通过外部的逻辑来生产产品,这时由外部来实例化具体工厂,生产具体产品交付给客户端。

      接着再来说说抽象工厂,在抽象工厂中最明显的一个特点是产品不止一类了,所以前文提到的计算机的例子就不适合使用抽象工厂模式(窃以为如此,有反对意见的欢迎提出)。

      在抽象工厂在提到一个“产品族”的概念,其实在抽象工厂中最为直观的体现就是产品A接口,产品B接口甚至是产品C、D接口。类图如下,从类图中不难发现,抽象工厂模式的具体工厂角色可以生产多种产品(工厂方法模式的具体工厂只能生产一种产品,不信去看类图)。就好像东方红拖拉机厂在工厂方法模式下只能生产拖拉机,但是在抽象工厂模式下不仅能生产拖拉机,还能生产卡车(如果加一个坦克的生产线,还能生产坦克)。

      此处就用比较熟悉的农场的例子,农场生产水果和蔬菜,水果分为北方水果和热带水果,蔬菜也一样,所以农场也分为北方农场和热带农场。

      代码如下:

    public interface IFruit{string Show();}public interface IVeggie{string Show();}public class NFruit : IFruit{private string name;public string Name{get { return "北方" + name; }set { name = value; }}public string Show(){return Name;}}public class TFruit : IFruit{string name;public string Name{get { return "热带" + name; }set { name = value; }}public string Show(){return Name;}}public class NVeggie : IVeggie{string name;public string Name{get { return "北方" + name; }set { name = value; }}public string Show(){return Name;}}public class TVeggie : IVeggie{string name;public string Name{get { return "热带" + name; }set { name = value; }}public string Show(){return Name;}}public interface Factory{IFruit CreateFruit(string nm);IVeggie CreateVeggie(string nm);}public class NFactory : Factory{public IFruit CreateFruit(string nm){return new NFruit() { Name = nm };}public IVeggie CreateVeggie(string nm){return new NVeggie() { Name = nm };}}public class TFactory : Factory{public IFruit CreateFruit(string nm){return new TFruit() { Name = nm };}public IVeggie CreateVeggie(string nm){return new TVeggie() { Name = nm };}}
基本代码

      此例的逻辑判断部分没写。从类图上看,它是不属于抽象工厂模式的,从简化客户端的角度,这个逻辑判断是可以从客户端剥离的,很显然和工厂方法模式的逻辑判断属于同一地位(有种两头受气的感觉)。

     然后再简单说spring的依赖注入。在spring中需要获取一个产品(实例)如何获取?容器来提供。逻辑判断呢?可以放在客户端,也可以从客户端剥离,爱放哪放哪。容器只依赖于配置,逻辑判断不会影响容器。所以容器很好的将生产过程与客户端隔离,这就不存在耦合了。

      接下来再说一下,一直不停的重复的判断逻辑。在菜鸟D 的看法里,上述几个模式的耦合都是存在于判断逻辑中的。在简单工厂中,工厂和客户端之间耦合较低,但是工厂和具体的产品类是直接耦合的。在工厂方法模式、抽象工厂模式、spring中,逻辑判断只是一个辅助,逻辑判断将生产过程和客户端隔离,大大地降低了耦合程度。所以在衡量设计模式的耦合时,就需要衡量判断逻辑在模式中作用和角色。有些耦合是很难避免的,为了避免这些耦合甚至可能会造成更多的耦合。至于开闭原则,编码过程尽量去注意,否则为以后的开发带来麻烦就不是我们想要的了。

     一家之言,不值一哂,如有谬误,欢迎指正。

     菜鸟D希望这篇文章对您有所帮助。

扩展参考:

大话设计模式P72:

      工厂方法实现时,客户端需要决定实例化哪一个工厂来实现运算类(具体产品),选择判断的问题还是存在的,也就是说,工厂方法吧简单工厂的内部逻辑判断移到了客户端代码来进行.想要添加功能,本来是要改工厂类的,而现在是修改客户端.

三种工厂模式区别总结

http://blog.csdn.net/lingfengtengfei/article/details/12374469

spring.net的依赖注入

http://www.cnblogs.com/GoodHelper/archive/2009/10/26/SpringNET_DI.html

工厂方法模式

http://blog.csdn.net/zhengzhb/article/details/7348707

三种工厂模式

http://www.cnblogs.com/poissonnotes/archive/2010/12/01/1893871.html

 

转载于:https://www.cnblogs.com/cnDqf/p/4122771.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/259689.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

堆、栈及静态数据区详解 转

内存分为代码区、全局数据区、堆区和栈区。堆一般存放动态数据,栈里一般存放局部成员。 关于堆栈和堆的概念[问题] C中创建本地(或者说局域)变量是在堆栈(stack)中分配内存地址,而创建全局变量则是在堆&…

如何使用CSS实现居中

前言: 这一篇主要是翻译 《how-to-center-anything-with-css》这一篇文章的主要内容,再加上自己的一些概括理解;主要问题是解决垂直居中的问题。我们知道实现水平居中的方式很多种,比如: text-align:center; margin:0 …

java布局_运用 BoxLayout 进行 Swing 控件布局

引言在用户使用 Java Swing 进行用户界面开发过程中,会碰到如何对 Java Swing 的控件进行布局的问题。Swing 的控件放置在容器 (Container) 中,容器就是能够容纳控件或者其它容器的类,容器的具体例子有 Frame、Panel 等等。容器需要定义一个布…

js变量类型

js中有null和undefined,null是指对象不存在,undefined是指原生数据不存在 var h {name:lisi,age:28};console.log(h.name)//对象用的是点语法,php中是name->lisi 下面是数组,数组用的是【】语法 1 var arr [a,3,hello,true];…

OPENCV MFC 程序出错修改

error C2146: 语法错误 : 缺少“;”(在标识符“PVOID64”的前面) 来源:http://houjixin.blog.163.com/blog/static/356284102009112395049370/ DirectShow 2009-12-23 09:50:49 阅读311 评论0 字号:大中小打开winnt.h文件,发现问题就是在winnt.h头文件中…

测试人员报BUG的正确姿势

每次我提需求的时候,都会和开发一言不合就上BUG。曾经看到一个段子,告诉了我,吵架是不行滴!影响心情,正确报bug的姿势应该是这样:不要对程序员说,你的代码有BUG。他的第一反应是:1、…

java链表实现_链表的原理及java实现

一:单向链表基本介绍链表是一种数据结构,和数组同级。比如,Java中我们使用的ArrayList,其实现原理是数组。而LinkedList的实现原理就是链表了。链表在进行循环遍历时效率不高,但是插入和删除时优势明显。下面对单向链表…

python和django中的常见错误

int() argument must be a string or a number, not tupleError in formatting: coercing to Unicode: need string or buffer, int foundData truncated for column content at row 1sql语句中单引号的设置字段类型字段长度 ascii codec cant decode byte 0xe7 in position 0:…

20141126-解决联网问题-笔记

当你的网络出现故障或无法连通时,如何才能简单高效的找出故障?其实只需要一个ping命令,就可以判断TCP/IP协议故障…… 1、Ping 127.0.0.1: 127.0.0.1是本地循环地址,如果本地址无法Ping通,则表明本地机TCP/…

inittab脚本启动解析 (zz)

http://blog.chinaunix.net/uid-17188120-id-4073497.html 1,启动inittab第一步:启动内核第二步:执行init (配置文件/etc/inittab)第三步:启动相应的脚本,执行inittab脚本,并且执行其…

java缓存技术_java缓存技术

最近在做java缓存,了解了一下.以下仅是对map对方式讨论。没有对点阵图阵讨论。作缓存要做以下2点:1:清理及更新缓存时机的处理:. 虚拟机内存不足,清理缓存.. 缓存时间超时,或访问次数超出, 启动线程更新2:类和方法的反射 (线程嵌套调用)reflect.invoke的使用。代码如下&#xf…

xss challenge 解题思路(1-3)

challenge1: 用很基本的方法即可&#xff0c;截图如下&#xff1a; 提交后成功弹窗&#xff0c;完成。 challenge2 这次我们发现我们输入的内容被放入value”“ 中&#xff0c;所以需要将前面的结构闭合&#xff0c;构造如下&#xff1a; "><script>alert(docume…

宾得准饼干广角镜头DA15

DA15的挂机效果图&#xff0c;感觉还是超级的小&#xff0c;是最小的广角镜头了&#xff1a; 主要特点1. 超广视角当安装在宾得数码单反相机上时&#xff0c;这款全新的镜头提供相当于35mm胶片规格的约23mm画面视角&#xff0c;可使拍摄者拍摄出独特的诱人影像和超广角镜头独有…

无限“递归”的python程序

如果一个函数直接或者间接调用了自己&#xff0c;那么就形成了递归&#xff08;recursion&#xff09;&#xff0c;比如斐波那契数列的一个实现 def fib(n):if n < 2:return 1else:return fib(n - 1) fib(n - 2) 递归一定要有结束条件&#xff0c;否则就形成了死循环&#…

java slf4j_SLF4J 使用手册

原文链接 译者&#xff1a;zivyuJava的简单日志门面( Simple Logging Facade for Java SLF4J)作为一个简单的门面或抽象&#xff0c;用来服务于各种各样的日志框架&#xff0c;比如java.util.logging、logback和log4j。SLF4J允许最终用户在部署时集成自己想要的日志框架。需要…

[译]Java 垃圾回收介绍

说明&#xff1a;这篇文章来翻译来自于Javapapers 的Java Garbage Collection Introduction 在Java中&#xff0c;对象内存空间的分配与回收是由JVM中的垃圾回收进程自动完成的。和C语言不一样的是&#xff0c;开发中不需要在Java中写垃圾回收代码。这也是使Java更加流行而且帮…

打印三角形

直角三角形 #include<iostream> using namespace std; int main() { int i,j; for(i1;i<10;i) {for(j1;j<i;j) cout<<"*"; cout<<endl; } } ———————————————————————————…

Linux基础入门学习笔记之二

第三节 用户及文件权限管理 Linux用户管理 Linux是可以实现多用户登录的操作系统 查看用户who命令用于查看用户 shiyanlou是当前登录用户的用户名 pts/0中pts表示伪终端&#xff0c;后面的数字表示伪终端的序号。 后面是当前伪终端启动时间 创建用户创建用户需要root权限&#…

java选填_java基础填空选择题

Core Java试题选择填空题&#xff1a;全部为多选题&#xff0c;只有全部正确才能得分。1. 编译java程序的命令是__B_;运行java程序的命令是____A____;产生java文挡的命令是_____D___;查询java类型是否是serializable类型的命令是___C_____;产生java安全策略文件的命令是____E__…

这几天有django和python做了一个多用户博客系统(可选择模板) 没完成,先分享下...

这个TBlog已经全新改版了&#xff0c;更名为UUBlog 新版地址&#xff1a; 用Python和Django实现多用户博客系统——UUBlog 断断续续2周时间吧&#xff0c;用django做了一个多用户博客系统&#xff0c;现在还没有做完&#xff0c;做分享下,以后等完善了再慢慢说 做的时候房展了博…