设计模式(1)——工厂模式
什么是简单工厂模式?
在现实生活中工厂是负责生产产品的,同样在设计模式中,简单工厂模式我们也可以理解为负责生产对象的一个类, 我们平常编程中,当使用”new”关键字创建一个对象时,此时该类就依赖与这个对象,也就是他们之间的耦合度高,当需求变化时,我们就不得不去修改此类的源码,此时我们可以运用面向对象(OO)的很重要的原则去解决这一的问题,该原则就是——封装改变,既然要封装改变,自然也就要找到改变的代码,然后把改变的代码用类来封装,这样的一种思路也就是我们简单工厂模式的实现方式了。下面通过一个的例子来引出简单工厂模式。
工厂需要建造一批货,他们分别是四边形跟三边形,那么我们就要创建Quadrilateral类和Triangle类。首先四边形的定义是什么,一个有四条边的形状。三边形是一个有三条边的形状。
//四边形
class Quadrilateral
{
//边数
int Sides
{
get { return 4; }
}
}
//三边形
class Triangle
{
//边数
int Sides
{
get { return 3; }
}
}
有细心的人看到了,边数这个属性四边形和三边形都有。那假如我们要多造几个五边形六边形,那么就要好多类,而且代码很多重复,那么我们就要用到面向对象三大特性之一——继承。我们创建一个形状类。
class Quadrilateral:Sharp
{
public override int Sides
{
get { return 4; }
}
}
class Triangle:Sharp
{
public override int Sides
{
get { return 3; }
}
}
class Sharp
{
public virtual int Sides { get; }
}
于是我们就用以下方式对这两个例子进行初始化。
Sharp quadrilateral = new Quadrilateral();
Sharp triangle = new Triangle();
但是实际上,我们都要在创建实例的时候做点初始化的工作,比如赋值,查询数据库等。于是就会用构造函数来实现,就会写成下面这样。
Sharp quadrilateral = new Quadrilateral(属性);
Sharp triangle = new Triangle(属性);
但是如果初始化工作不是赋值这种简单的操作,而是很长的代码,如果也写到构造函数中就很难看了。而且不仅如此,假如这次需要一个四边形,是个梯形,下次需要个长方形,下次又需要个正方形,这些需要的参数种类可能不同,数量也不同,就要写多个构造函数,或者需要个边长为5mm的正方形或者边长为3mm的正方形等等,于是每次改需求,就要每次去找到Sharp quadrilateral = new Quadrilateral(属性)这块代码对属性进行修改。但是其实这些都是工厂的需求,跟形状这个类本身关系不大,于是简单工厂模式应运而生。
class SharpFactory
{
public static Sharp GetSharp(类型)
{
Sharp sharp = null;
switch (类型)
{
case 四边形: sharp = new Quadrilateral();break;
case 三角形: sharp = new Triangle();break;
case 梯形: sharp = new Quadrilateral(new double[4] { 1, 2, 3, 3});break;
case 长方形: sharp = new Quadrilateral(new double[4] { 2, 2, 3, 3 });break;
case 3mm的正方形: sharp = new Quadrilateral(new double[4] { 3, 3, 3, 3 });break;
case 5mm的正方形: sharp = new Quadrilateral(new double[4] { 5, 5, 5, 5 });break;
}
return sharp;
}
}
//修改Quadrilateral类
class Quadrilateral:Sharp
{
public override int Sides
{
get { return 4; }
}
public double[] Border { get; set; }
public Quadrilateral(double[] border)
{
this.Border = border;
}
public Quadrilateral() { }
}
//调用
Sharp sharp = SharpFactory.GetSharp(类型);
其实上面还有几个不太合理的地方,比如这个Sharp类,他本身就是个形状,他不是一个实实在在存在的东西,他应该不能实例化,应该作为一个抽象类存在,当然了单纯改个abstract没什么意义,于是我决定对本次的例子进行扩展,增加一个周长的属性与一个求周长的方法。
class Quadrilateral:Sharp
{
public override int Sides
{
get { return 4; }
}
public Quadrilateral(double[] border)
{
if (border.Count() != Sides)
return;
this.Border = border;
}
public Quadrilateral() { }
public override void GetPerimeter()
{
Perimeter= Border.Sum();
}
}
class Triangle:Sharp
{
public override int Sides
{
get { return 3; }
}
public Triangle(double[] border)
{
if (border.Count() != Sides)
return;
this.Border = border;
}
public Triangle() { }
public override void GetPerimeter()
{
Perimeter = Border.Sum();
}
}
abstract class Sharp
{
public virtual int Sides { get; }
public double[] Border { get; set; }
public double Perimeter { get; set; }
public abstract void GetPerimeter();
}
发现好多重复代码,那继续改。
class Quadrilateral:Sharp
{
public override int Sides
{
get { return 4; }
}
}
class Triangle:Sharp
{
public override int Sides
{
get { return 3; }
}
}
abstract class Sharp
{
private double[] border;
public virtual int Sides { get; }
public double[] Border
{
get { return border; }
set
{
if (border.Count() == Sides)
border = value;
}
}
public double Perimeter { get; set; }
public void GetPerimeter()
{
Perimeter = Border.Sum();
}
}
class SharpFactory
{
public static Sharp GetSharp(类型)
{
Sharp sharp = null;
switch (类型)
{
case 四边形: sharp = new Quadrilateral(); break;
case 三角形: sharp = new Triangle(); break;
case 梯形: sharp = new Quadrilateral(); sharp.Border = new double[4] { 1, 2, 3, 3 }; break;
case 长方形: sharp = new Quadrilateral(); sharp.Border = new double[4] { 2, 2, 3, 3 }; break;
case 3mm的正方形: sharp = new Quadrilateral(); sharp.Border = new double[4] { 3, 3, 3, 3 }; break;
case 5mm的正方形: sharp = new Quadrilateral(); sharp.Border = new double[4] { 5, 5, 5, 5 }; break;
}
return sharp;
}
}
优点与缺点
看完简单工厂模式的实现之后,你和你的小伙伴们肯定会有这样的疑惑(因为我学习的时候也有)——这样我们只是把变化移到了工厂类中罢了,好像没有变化的问题,因为如果工厂想要建造其他形状,此时我们还是需要修改工厂类中的方法(也就是多加case语句,没应用简单工厂模式之前,修改的是客户类)。我首先要说:你和你的小伙伴很对,这个就是简单工厂模式的缺点所在(这个缺点后面介绍的工厂方法可以很好地解决),然而,简单工厂模式与之前的实现也有它的优点:
- 简单工厂模式解决了客户端直接依赖于具体对象的问题,客户端可以消除直接创建对象的责任,而仅仅是消费产品。简单工厂模式实现了对责任的分割。
- 简单工厂模式也起到了代码复用的作用,因为之前的实现(形状的类型)中,换了一种类型同样要去在自己的类中实现求周长的方法,然后有了简单工厂之后,建造形状就不需要此时简单工厂的求周长方法就让所有客户共用了。(同时这点也是简单工厂方法的缺点——因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都会受到影响,也没什么不好理解的,就如事物都有两面性一样道理)
虽然上面已经介绍了简单工厂模式的缺点,下面还是总结下简单工厂模式的缺点:
- 工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都会受到影响
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,这样就会造成工厂逻辑过于复杂。
了解了简单工厂模式之后的优缺点之后,我们之后就可以知道简单工厂的应用场景了:
- 当工厂类负责创建的对象比较少时可以考虑使用简单工厂模式()
- 客户如果只知道传入工厂类的参数,对于如何创建对象的逻辑不关心时可以考虑使用简单工厂模式
本文主要借鉴了《Gof设计模式》,《Learning hard C#学习笔记》C#设计模式(2)——简单工厂模式
上一篇: List相关面试题--这一篇全了解
下一篇: 华为面试题