一、针对类的简单工厂
在开发过程中,如果想要创建一个对象,我们最直接的办法就是直接new出来它,就像下面这样↓
// 声明一个Circle类
class Circle
{
}
// 创建一个circle对象
var circle = new Circle();
这样当然是没有任何问题的。但是,如果Circle类有很多属性和字段需要初始化,那么简单的new Circle()就满足不了我们的要求了,我们就需要为Circle类提供一个有参构造函数,或者在new出一个空白的Circle对象之后,对其需要初始化的属性进行赋值,就像下面那样↓
// 声明一个带有多个参数的Circle类
class Circle
{// 名称public string Name { get; set; }// 面积public string Area { get; set; }// 周长public string Perimeter { get; set; }public Circle(string name, string area, string perimeter){Name = name;Area = area;Perimeter = perimeter;}
}
// 创建Circle对象并初始化// 方法1:使用有参构造
var circle1 = new Circle("圆形1", 30, 50);
// 方法2:使用无参构造+属性单独初始化
var circle2 = new Circle();
circle2.Name = "圆形2";
circle2.Area = 70;
circle2.Perimeter = 80;
这样其实就看出端倪了,如果在我当前项目中,我的Circle类就是会被初始化成Name = "圆形";Area = 70;Perimeter = 80;的情况呢,我管这种情况叫A类型Circle,那我直接给我的Circle类的属性设置默认值不就好了吗?省的我在创建Circle的地方每次都要写这三个参数的值,就像下面那样↓
// 默认使用A方案,为Circle的属性赋默认值
class Circle
{// 名称public string Name { get; set; } = "圆形";// 面积public int Area { get; set; } = 70;// 周长public int Perimeter { get; set; } = 80;public Circle(string name, int area, int perimeter){Name = name;Area = area;Perimeter = perimeter;}
}
这样确实很省心,每次都能输出一个初始化好的Circle对象,但是,如果后面业务变动,你的Circle对象在某些情况下需要初始化为Name = "大圆形";Area = 120;Perimeter = 150;呢?这时候原本的A类型Circle就不能直接用了,但是你肯定会说,这有何难?我不在Circle类中初始化属性了,我单独写一个类,就叫CircleFactory,由它来负责Circle对象的创建工作,我给它什么要求,它就给我new一个什么样的Circle对象返回给我好了,就像下面那样↓
// Circle工厂
class CircleFactory
{public static Circle CreateCircle(string type){if (type == "A"){var circleA = new Circle("圆形", 70, 80);return circleA;}else if (type == "B"){var circleB = new Circle("大圆形", 120, 150);return circleB;}else{return null;}}
}
而我在调用时,仅需传递给工厂类,我要哪个型号的Circle对象即可,这大大简化了调用处的代码↓
// 调用Circle工厂,让Circle工厂来初始化我的Circle类,我只提供我需要A还是B
var circleA = CircleFactory.CreateCircle("A");
恭喜,你已经学会了简单工厂模式,上文描述的就是简单工厂模式的应用场景之一,将某个类的有限的初始化情况封装到工厂类中,通过调用工厂类的创建方法,给方法传参,来获取对应的初始化好的对象,简化调用处的代码。其UML图如下↓
二、针对接口的简单工厂
上文的代码是针对一个类的情况,如果是不同的类,但是这些类都实现了某个接口,也可以使用该方式来将创建对象的工作交给工厂类,就像下面这样↓
// 定义IShape接口
interface IShape
{// 名称public string Name { get; set; }// 面积public int Area { get; set; }// 周长public int Perimeter { get; set; }
}
// 定义Circle类,实现IShape接口
class Circle : IShape
{public string Name { get; set; }public int Area { get; set; }public int Perimeter { get; set; }
}
// 定义Rectangle类,实现IShape接口
class Rectangle : IShape
{public string Name { get; set; }public int Area { get; set; }public int Perimeter { get; set; }
}
// Shape工厂类
class ShapeFactory
{public static IShape CreateShape(string type){if (type == "circle"){var circle = new Circle();circle.Name = "圆形";circle.Area = 70;circle.Perimeter = 80;return circle;}else if (type == "rectangle"){var rectangle = new Rectangle();rectangle.Name = "矩形";rectangle.Area = 120;rectangle.Perimeter = 150;return rectangle;}else{return null;}}
}
// 调用Shape工厂,按需获取想要的对象
var circle = ShapeFactory.CreateShape("circle");
var rectangle = ShapeFactory.CreateShape("rectangle");
这就是简单工厂方法中的另外一种情况,其UML图如下↓
总结
简单工厂模式,是为了在创建需要初始化属性的对象时,无需调用者关心初始化的细节,把初始化的逻辑封装到工厂类中,统一管理和调用即可。
好处:
- 创建对象时,不需要关心创建对象的具体细节,例如初始化某个属性等等,只需要提供预设的参数即可
缺点:
- 如果需要创建的对象有很多,那么工厂类就会变得非常庞大,该类的职责就不太清晰
- 如果需要支持新的对象,则需要修改工厂类,违反开闭原则(对扩展开放,对修改关闭)