引言

工厂模式是比较常用的设计模式,主要用于返回实例对象,将多种类型的创建集中放在一个地方创建。工厂模式一般分为简单工厂模式,工厂方法模式,抽象工厂模式。各有优缺点,今天这里还加入了简单工厂模式的另一种实现,添加反射实现简单工厂。

例子

         一个很简单的例子:有个富豪想买奔驰,宝马,福特汽车,开出去玩。

代码:

什么模式都不用

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Client : MonoBehaviour {public abstract class Car{public abstract void Dirve();}public class Benz : Car{public override void Dirve(){Debug.Log("Dirve a Benz");}}public class BMW : Car{public override void Dirve(){Debug.Log("Dirve a BMW");}}public class Ford : Car{public override void Dirve(){Debug.Log("Dirve a Ford");}}void Start () {Car car1 = new Benz();car1.Dirve();Car car2 = new BMW();car2.Dirve();Car car3 = new Ford();car3.Dirve();}
}

上述代码已实现功能,但是上述代码有一些这样的情况:

1.如果有另一个富豪他也想买这三种车来开,那么在他的类里面也要写这三个类然后new3辆车——代码重复

2.一个富豪,他里面有三种汽车如何制造出来的代码,作为一个客户,他却要懂生产——职责混淆

但是,聪明的你肯定马上就想到,直接把这三个汽车类单独抽出来,这样,客户直接new出来就可以了,职责也不混淆,别的富豪要车也可以直接new出来,代码也不重复。

那我们接下来看,假设我的汽车抽象类,稍微复杂那么一丢丢,如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public abstract class Car {public float Length;public float Width;public float High;public float MaxSpeed;public abstract void Dirve();public abstract void Test(); //出厂测试
}

1.new一辆奔驰车出来,这些字段都需要赋值,还要运行一个出厂测试方法,如果这些赋值,方法在客户client类里面写,那么其他所有客户都要写这些代码,代码重复。

但是你肯定马上说:“不对,我可以写在汽车类的构造函数里面”,当然可以,不过,如果要干的事情特别多,几十行上百行的代码,全放构造函数里面,有点违背设计原则,在构造函数做太复杂的操作,当出错时发现错误有时会很困难。特别是定义为全局变量时,程序还没有运行、就出错了。构造函数应该尽量简单,一眼望穿,最好能保证永不出现构造失败的情况。

2.如果Benz(奔驰车)多了一个子类,奔驰二代Benz2,现在买奔驰车返回这个类的对象,那么所有客户端的new Benz(),都要换成new Benz2(),而如果做成工厂模式,直接在返回奔驰车的代码哪里更改一下返回Benz2类的对象就可以了,反正返回的都是Car(抽象父类)——方便维护。

3.如果所有的汽车类,在返回对象之前,又要添加新的逻辑了,那么需要一个个类的找,修改,如果全集中在工厂类中,直接在工厂类中修改即可,避免遗漏,还是——方便维护。

所以工厂模式主要是有代码重用,分割职责解耦,便于维护的特点。

那么接下来来看看工厂模式:

还是上面的例子:有个富豪想买奔驰,宝马,福特汽车,开出去玩。

一、简单工厂

汽车类

public abstract class Car {public abstract void Dirve();
}

奔驰

public class Benz : Car{public override void Dirve(){Debug.Log("Dirve a Benz");}
}

宝马

public class BMW : Car {public override void Dirve(){Debug.Log("Dirve a BMW");}
}

福特

public class Ford : Car {public override void Dirve(){Debug.Log("Dirve a Ford");}
}

简单工厂类

public class SimpleFactory {public static Car CreatCar(string car){Car newCar = null;if (car == "Benz"){newCar = new Benz();}else if (car == "BMW"){newCar = new BMW();}else if (car == "Ford"){newCar = new Ford();}return newCar;}
}

客户类

public class ClientSimple : MonoBehaviour {void Start () {//简单工厂Car car1 = SimpleFactory.CreatCar("Benz");car1.Dirve();Car car2 = SimpleFactory.CreatCar("BMW");car2.Dirve();Car car3 = SimpleFactory.CreatCar("Ford"); ;car3.Dirve();}
}

上述代码,客户不需要知道怎么生产汽车(解耦),多个客户要车都可以调用工厂得到汽车,如果汽车初始要做很多事情,都可以在工厂类里面newcar之后调各自类的方法,赋值,如果什么模式都不用,直接new的方式,就要写在类的构造函数里面或者直接在客户类写,不太好(重复)。

上述代码也会有一些情况,如果我需要新增一种车,比如莱斯莱斯,那么我就要在工厂类里面多加一个else if条件判断。工厂类就要进行修改——扩展性不强,这个工厂类包含类所有类的创建,很重要,频繁改动如果出错影响面广。

如果种类不多,简单工厂用起来还是不错的。

二、工厂方法

汽车类同上,

抽象工厂类:

public abstract class Factory {public abstract Car CreatCar();
}

奔驰工厂

public class BenzFactory : Factory {public override Car CreatCar(){return new Benz();}
}

宝马工厂

public class BMWFactory : Factory {public override Car CreatCar(){return new BMW();}
}

福特工厂

public class FordFactory : Factory {public override Car CreatCar(){return new Ford();}
}

客户类

public class ClientSimple : MonoBehaviour {void Start () {//工厂方法Car car1 = new BenzFactory().CreatCar();car1.Dirve();Car car2 = new BMWFactory().CreatCar();car2.Dirve();Car car3 = new FordFactory().CreatCar();car3.Dirve();}
}

上述代码,添加新类型的莱斯莱斯车,需要新增莱斯莱斯车类和莱斯莱斯工厂类,工厂父类Factory不需要修改,这样对于已有的工厂不会产生任何潜在的改动影响——便于扩展。

对于这种方式,和直接new Benz(), new BMW(), new Ford()有点像,每一种车有一个工厂类,不过还是上面讲的,如果返回一个实例要做很多事情,不好直接写在构造函数里面,可以写在具体的工厂类里面,而且如果工厂父类要添加新的逻辑,所有工厂同时享有。

工厂方法就是每加一种类型,要添加汽车类,还要添加具体工厂类,增加开销。

三、抽象工厂

抽象工厂其实就是工厂方法的扩展,以前工厂方法父类,只生产汽车,现在工厂作死新开了一条火箭生产流水线,要可以制作火箭了,那么工厂父类就变成这样:

public abstract class Factory {public abstract Car CreatCar();public abstract Rocket CreatRocket();
}

那么奔驰工厂,宝马工厂,福特工厂类都要添加生产火箭的方法,奔驰牌火箭,宝马牌火箭,福特牌火箭都属于继承自抽象火箭类Rocket,和之前的Car是一模一样的逻辑。代码就不放了,看这个工厂父类就知道了,这就是抽象工厂和工厂方法的区别。

这个抽象工厂,如果增加一种新产品种类,工厂父类和所有子类工厂,都需要改动。

是否使用看自己项目需求了。

四、反射+简单工厂

public class SimpleFactory {public static Car CreatCar(string car){Car newCar = null;if (car == "Benz"){newCar = new Benz();}else if (car == "BMW"){newCar = new BMW();}else if (car == "Ford"){newCar = new Ford();}return newCar;}
}

上面的是之前的简单工厂,主要就是不便于扩展,新增一种车,就要在工厂类里面多加一个条件判断。

现在添加反射实现简单工厂,代码如下:

public class ReflectionSimpleFactory {public static Car CreatCar(string carClass){//获取当前程序集Assembly ass = Assembly.GetCallingAssembly();//获取程序集中的类Type t = ass.GetType(carClass);//创建类的实例对象Car o = (Car)Activator.CreateInstance(t);return o;}
}

客户类还是和之前简单工厂一样调用

public class ClientSimple : MonoBehaviour {void Start () {//反射+简单工厂Car car1 = ReflectionSimpleFactory.CreatCar("Benz");car1.Dirve();Car car2 = ReflectionSimpleFactory.CreatCar("BMW");car2.Dirve();Car car3 = ReflectionSimpleFactory.CreatCar("Ford");car3.Dirve();}
}

如果新增一种劳斯莱斯车型,只需要添加新类RR这一个类就可以,工厂类不用做其他改动,解决了简单工厂的扩展性问题。

public class RR : Car {public override void Dirve(){Debug.Log("Dirve a RR");}
}
public class ClientSimple : MonoBehaviour {void Start () {//反射+简单工厂Car car1 = ReflectionSimpleFactory.CreatCar("Benz");car1.Dirve();Car car2 = ReflectionSimpleFactory.CreatCar("BMW");car2.Dirve();Car car3 = ReflectionSimpleFactory.CreatCar("Ford");car3.Dirve();Car car4 = ReflectionSimpleFactory.CreatCar("RR");car4.Dirve();}
}

反射也存在效率问题,我这里创建基本什么都没干,循环创建3辆车,100万次试了一下,测试代码如下:

using System.Diagnostics;
using UnityEngine;public class Client_Factory : MonoBehaviour {void Start () {Stopwatch st = new Stopwatch();st.Reset();st.Start();for (int i = 0; i < 1000000; i++){简单工厂//Car car1 = SimpleFactory.CreatCar("Benz");car1.Dirve();//Car car2 = SimpleFactory.CreatCar("BMW");car2.Dirve();//Car car3 = SimpleFactory.CreatCar("Ford"); ;car3.Dirve();工厂方法//Car car1 = new BenzFactory().CreatCar();car1.Dirve();//Car car2 = new BMWFactory().CreatCar();car2.Dirve();//Car car3 = new FordFactory().CreatCar();car3.Dirve();//反射+简单工厂Car car1 = ReflectionSimpleFactory.CreatCar("Benz");//car1.Dirve();Car car2 = ReflectionSimpleFactory.CreatCar("BMW");//car2.Dirve();Car car3 = ReflectionSimpleFactory.CreatCar("Ford");//car3.Dirve();}st.Stop();UnityEngine.Debug.Log(st.ElapsedMilliseconds.ToString()+ " ms");}
}

用时分别是简单工厂:237ms,工厂方法:326ms,反射+简单工厂:10305ms,前两种基本差别不大,反射之后差了几十倍。这个类创建很简单,如果类复杂,反射可能更耗时,不过这是100万次,日常开发基本也不太可能调用这么多次,具体是否用,自己项目衡量。

C#工厂模式——简单工厂、工厂方法、反射+简单工厂、抽象工厂相关推荐

  1. 设计模式-抽象工厂模式的应用场景及Java中对抽象工厂的应用

    1. 什么是抽象工厂模式 抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定他们的类 抽象工厂模式(Abstract Factory Pattern)隶属于设计模式中的创建型模式,用 ...

  2. 王争 | 设计模式之美 - 工厂模式:我为什么说没事不要随便用工厂模式创建对象?

    1. 简单工厂(Simple Factory) 在下面这段代码中,我们根据配置文件的后缀(json.xml.yaml.properties),选择不同的解析器(JsonRuleConfigParser ...

  3. 教程2,工厂方法实现发奖,抽象工厂实现redis集群,JDK动态代理应用

    简单 工厂方法 抽象 区别 三个工厂的区别 简单:提供方法的工厂.并不算设计模式, 我要A对象 ,你给我A对象 ,B对象也是这里要.拿哪一个你帮我选. 产品工厂--> 产品接口(if else) ...

  4. 简单的java方法_Java简单实用方法一

    整理以前的笔记,在学习Java时候,经常会用到一些方法.虽然简单但是经常使用.因此做成笔记,方便以后查阅 这篇博文先说明构造和使用这些方法. 1,判断String类型数据是否为空 String类型的数 ...

  5. 工厂方法模式与抽象工厂模式

    本文是转的 一.引子        话说十年前,有一个暴发户,他家有三辆汽车--Benz奔驰.Bmw宝马.Audi奥迪,还雇了司机为他开车.不过,暴发户坐车时总是怪怪的:上Benz车后跟司机说&quo ...

  6. 最简单java设计模式:抽象工厂模式

    前言 在前一篇文章讲解了一下简单工厂模式和工厂方法模式,这篇文章再把抽象工厂模式讲解一下. 一.什么是抽象工厂模式 抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的.抽象工厂模式可以向客户端提 ...

  7. Java设计模式—工厂方法模式抽象工厂模式

    工厂方法模式与抽象工厂模式都是设计模式中重要而且常见的模式.       工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类. 通用类图如下: 在 ...

  8. Android工厂设计模式(简单工厂,工厂方法,抽象工厂,BitmapFactory简单工厂分析,Retrofit抽象工厂分析)

    文章目录 创建型设计模式(简单工厂,工厂方法,抽象工厂) 一.简单工厂模式 引出简单工厂模式 二.工厂方法模式 三.抽象工厂模式 Android源码中用到的工厂模式举例 一.BitmapFactory ...

  9. 工厂模式 android,当Android遇见工厂模式

    设计模式.png 我们先看一下一个Android系统应用中的工厂模式列子,再讲解工厂模式. package com.android.mms.ui; import android.content.Con ...

  10. 创建相似对象,就交给『工厂模式』吧

    源码: 源代码C# 系列导航: 目录 定义(Factory Pattern): 用来创建目标对象的类,将相似对象的创建工作统一到一个类来完成. 一.简单工厂模式: 代码: /// <summar ...

最新文章

  1. JavaScript四舍五入的改进
  2. NTU 课程笔记:CV6422 样本分布
  3. 计算机中位运算的一些性质与技巧
  4. python列表可以加可以乘
  5. RuntimeException:java.lang.ClassNotFoundException: Class wordcount.WordCountMapper not fonud
  6. 云洗衣机HTML5源码 朋友圈在线娱乐洗衣服
  7. Java实现文件复制
  8. RHEL5上Oracle9i的安装
  9. Android Studio和Kotlin入门
  10. 加速Webpack-缩小文件搜索范围
  11. 使用screen来保存你的远程会话
  12. SQL 2016——新功能
  13. 我的 CSDN 两周年创作纪念日
  14. 如何免费复制网页内容
  15. mysql 表分区修复,硬盘分区表损坏后的数据恢复方法
  16. 一文了解DeFi主经济商,为何说它是DEX主导市场的关键
  17. JAVA计算机毕业设计腾讯网游辅助小助手(附源码、数据库)
  18. 针对STM32F4的肉电路问题
  19. tlc5620输出三角波流程图_基于TLC5620的数模转换器设计
  20. 拒绝无脑跳转“下载某度APP“!

热门文章

  1. 赛道和资本的玩儿法已经过气,SaaS公司活下去还能靠什么?
  2. 利用555定时器的双电源电路原理
  3. QQ坦白说BUG 找出对方
  4. 四天学会JavaScript(Day1~Day4)
  5. 输入年份和月份输出该月有多少天python_输入年份和月份,输出该月有多少天,判断这一天是该年的第几天...
  6. 测试网速_怎样测试两台电脑之间的网速
  7. UMTS 与 WCDMA的区别
  8. 紫书刷题记录 UVa297 四分树
  9. 『词向量』用Word2Vec训练中文词向量(一)—— 采用搜狗新闻数据集
  10. 恢复未保存的word