最近一直再将设计模式,于是趁热打铁,对这三种设计模式做一个总结。
首先我先用一句话总结一下这三个模式:简单工厂是一个工厂只能造一种奔驰,工厂方法是一个工厂可以造多种车,比如劳斯莱斯、奥迪等,而抽象工厂是说工厂不光可以造越野式奔驰,还可以造家用式奔驰、还有商用式奔驰。
那么究竟简单工厂是什么呢?为什么它不是23的设计模式中的一个?
用一个类图和一段代码我们来解释一下:
下面结合代码说一下
1、抽象产品
<span style="font-size:14px;"> public abstract class Car
{
private string name;
public string getName() {
return name;
}
public void setName(string name) {
this.name = name;
}
public abstract void Drive();
}</span>
2、具体产品,benz/bmw
<span style="font-size:14px;"> public class benz:Car
{
public override void Drive()
{
Console.WriteLine(this.getName() + "-------------go---------------");
}
}</span>
<span style="font-size:14px;"> public class bmw:Car
{
public override void Drive()
{
Console.WriteLine(this.getName() + "-------------go---------------");
}
}</span>
3、简单工厂
<span style="font-size:14px;"> public class SimpleFactory
{
public static Car createCar(string car)
{
Car c = null;
//if ("benz".Equals(car))
//{
// c = new benz();
//}
//else if("bmw".Equals(car))
//{
// c = new bmw();
//}
//return c;
if ("benz".Equals(car))
{
c = new benz();
}
else if("bmw".Equals(car))
{
c = new bmw();
}
return c;
}
}</span>
4、客户端调用
<span style="font-size:14px;"> class Client
{
static void Main(string[] args)
{
//造奔驰
Car car = SimpleFactory.createCar("benz");
car.setName("benz");
car.Drive();
}
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span></span>
这便是简单工厂模式了。那么它带了了什么好处呢?
首先,符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责“消费”产品(正如暴发户所为)。
下面我们从开闭原则上来分析下简单工厂模式。当暴发户增加了一辆车的时候,只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。(即创建一个新的车类,继承抽象产品Car)那么 对于产品部分来说,它是符合开闭原则的——对扩展开放、对修改关闭;但是工厂类不太理想,因为每增加一辆车,都要在工厂类中增加相应的商业逻辑和判 断逻辑,这显自然是违背开闭原则的.
那么大家有没有想过这样一个问题,为什么简单工厂不属于23个设计模式之一呢?下面说说我的理解:
我想举个例子就是面向对象的三大特性:封装、多态、继承,为什么不把抽象放在里边呢?因为它是最基础的,而简单工厂也是最基础的,而且简单工厂违反开闭原则,而设计模式存在的意义有一个重要的原因是复用,但是简单工厂不能提高复用性
在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了。正如我前面提到的简单工厂模式适用于业务简单的情况下或者具体产品很少增加的情况。而对于复杂的业务环境可能不太适应了。这就应该由工厂方法模式来出场了!!
下面我们来说下工厂方法的类图
通过上图我们可以看出,不同的工厂造不同品牌的车,当我需要一辆奥迪时,我不需呀在工厂中修改逻辑,只需要扩展类就可以了。这样符合了开闭原则,也提高了代码的复用性。
这里我们只变动了工厂代码和客户端,下面我们展示一下:
1、抽象工厂
<span style="font-size:14px;"> public abstract class AbstractFactory
{
//抽象造车
public abstract Car createCar(String car);
}</span>
2、造奔驰的工厂和造宝马的工厂
<span style="font-size:14px;"> public class bmwFactory:AbstractFactory
{
public Car createCar(String car)
{
return new bmw();
}
}</span>
<span style="font-size:14px;"> public class benzFactory:AbstractFactory
{
public Car createCar(String car)
{
return new benz();
}
}</span>
3、客户端与简单工厂的变动就是需要选择你要造车的工厂
<span style="font-size:14px;"> class FactoryMethodClient
{
static void Main(string[] args)
{
//选择一个工厂
AbstractFactory factory = new benzFactory();
//造奔驰
Car car = factory.createCar("benz");
car.setName("benz");
car.Drive();
}
}</span>
使用开闭原则来分析下工厂方法模式。当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。(即当有新产品时,只要创建并基础抽象产品;新建具体工厂继承抽象工厂;而不用修改任何一个类)工厂方法模式是完全符合开闭原则的!
使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。
但是随着生活质量的提高,人们不光想要工厂生产一种类型的车子,比如我想要奔驰牌跑车,奔驰牌家用,奔驰牌商用,宝马也是,那我们的工厂方法模式就不能满足了,这时候,我们就需要用抽象工厂来实现了。
很明显可以看出,我们的工厂分不同的类型来造车,就跟饭店里的厨子一样,有的人要川系豆角、豆腐,有人要鲁系豆角、豆腐,我们只需要让不同系的师傅去做就可以了,下面看下我们的代码。
1、抽象的奔驰
<span style="font-size:14px;">abstract class AbstractBenzCar
{
private String name;
public abstract void drive();
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}</span>
2、不同类型的奔驰
<span style="font-size:14px;">class BenzSportCar: AbstractBenzCar{
public void drive(){
System.out.println(this.getName()+"----BenzSportCar-----------------------");
}
}
class BenzBusinessCar: AbstractBenzCar{
public void drive(){
System.out.println(this.getName()+"----BenzBusinessCar-----------------------");
}
} </span>
宝马同理:
<span style="font-size:14px;">class BmwSportCar : AbstractBenzCar
{
public void drive(){
System.out.println(this.getName()+"----BenzSportCar-----------------------");
}
}
class BmwBusinessCar : AbstractBenzCar
{
public void drive(){
System.out.println(this.getName()+"----BenzBusinessCar-----------------------");
}
} </span>
3、抽象工厂:可以造不同品牌的车
<span style="font-size:14px;"> public abstract class AbstractFactory
{
//抽象造车
public abstract BenzCar createBenzCar(String car) ;
public abstract BmwCar createBmwCar(String car);
public abstract AudiCar createAudiCar(String car) ;
}</span>
4、具体工厂
<span style="font-size:14px;"> public class sportsFactory:AbstractFactory
{
public BenzCar createBenzCar(String car) {
return new BenzSportCar();
}
public BmwCar createBmwCar(String car) {
return new BmwSportCar();
}
public AudiCar createAudiCar(String car) {
return new AudiSportCar();
}
}</span>
商用同理。
5、客户端调用
<span style="font-size:14px;">class Client
{
static void Main(string[] args)
{
//造奔驰
AbstractFactory factory = new sportsFactory();
benz car = factory.createBenzCar("");
car.drive();
}
}</span>
通过上面的例子,我们可以看出,我们让品牌之间,系别之间彻底解耦,所有的东西都以对象的形式,就是一台电视,是由不同厂家、不同零件拼凑而成一样。