我的设计模式学习之路--简单工厂模式
2012-12-12 22:53
316 查看
最近在学习设计模式,正在看design pattern 和大话设计模式这两本书,感觉大话设计模式这本书确实讲的还是很不错的,简单通俗易懂,非常适合我这样的初学者,但是设计模式这个玩意仅仅只是看还是不够的,感觉看懂非常简单,但真的自己写起来还是要费电功夫的,为了加强自己的记忆,于是我决定自己动手练习一下,顺便就谢谢blog记忆一下。
后续我会继续更新这一系列的blog。(因为之前没有学过UML,所以对设计程序架构这一块实在是不会,看的书上有很多类图,类图可以直接反应一个系统的结构,对于这些模式的类图就只好以后慢慢更新上来了,目前也准备开始慢慢的去学一学UML,现在发现这个东西还真是挺重要的)。好了,废话不多说,我们开始吧,对于blog中写得欠佳,或者有误的地方欢迎大家指正。
工厂模式,顾名思义就是使用一个工厂生产东西。那么我们就要汽车工厂为例。我们使用汽车工厂生产各种不同类型的汽车。工厂模式的主要作用是使用一个统一的工厂去控制生产某大类物品中的各种不同的具体物品,比如使用汽车工厂生产奔驰,奥迪,宝马等等不懂类型的汽车。对于工厂的使用者来说他并不关心汽车是怎么具体的被生产出来的,那么我们就要对汽车工厂的使用者隐藏各种不同类型的汽车的细节,使用者只需要简单的选择自己需要生产何种类型的车,然后拿到被生产出来的物品就可以了。
汽车的种类那么多,生产者没那么多精力去管理那么多的生产线,那么就必须有一个统一的总控制部件来控制不同的生产线来生产各种汽车,这样我们就必须抽象出一个汽车大类,而其他的具体的种类的汽车继承这个大类,然后我们就可以对不同种类的车进行统一的管理,同样不同种类的车应该在自己的生产线上生产出来,启动哪个生产线进行生产就会产出哪种类型的车,这样我们就需要一个管理生产线的总控室。这样各个不同的类之间的关系就可以抽象出来了。
类图(后续再补充)
汽车大类:
具体的汽车类:
具体的汽车生产线类:
具体生产线的统一管理类:
package com.kexin.designpatterns.simpleFactory;
/**
* 抽象汽车工厂
* @author Administrator
* 实际上不同的车型,生产的工序中还是有很多的不同点的,所以要让不同的汽车工厂
* 都各自实现这个方法,已完成生产不同种类的汽车的需要
*/
public class AutomobileFactory {
private static AutomobileFactory automobileFactory ;
/**
* 提供不同的工厂名字,决定生产何种类型的车。
* 这种方式,每次有新的类型的汽车生产工厂建立起来后就必须改的这个类。
* @param FactoryName
* @return
*/
public Automobile produceAutomobile(String factoryName)
{
Automobile autoMobile = null;
switch(factoryName)
{
case "Audi":
autoMobile = AudiFactory.getInstance().produceAudi();
break;
case "Benz":
autoMobile = BenzFactory.getInstance().produceBenz();
break;
case "BMW":
autoMobile = BMWFactory.getInstance().produceBMW();
break;
}
return autoMobile;
}
public static AutomobileFactory getInstance()
{
if(automobileFactory == null)
{
automobileFactory = new AutomobileFactory();
}
return automobileFactory;
}
}
从上面的代码我们可以发现这里有一个缺点:如果我们的工程已经投入使用了,而我们这个时候需要新增一条大众汽车生产线,那么我们就必须去修改最后那个统一生产线管理类,这就破坏了软件设计中的开放闭合原则:开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。
放封闭原则,其核心的思想是:
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。因此,开放封闭原则主要体现在两个方面: 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。 对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。这就是简单工厂的一个缺点。为了解决这个问题我对统一工厂管理类进行了一点改进。利用反射(这是对编程语言有依赖的,现在有些面向对象的编程语言并不支持反射,但是java支持),我们在统一管理工厂里面把具体生产线类的Class对象作为参数传进去,通过这个对象来动态生成这个生产线类的实例,然后使用这个实例调用自己的生产方法来生产汽车。这样当有新的汽车生产线加进来的时候我们只需要传入这个生产线的Class对象就可以了(前提是你必须有这种新汽车结构模板并且已经为它搭建好了生产线)而不需要去修改统一管理工厂类了,而传入的参数是可以有工厂的使用者决定的,这就解决了开发闭合原则被破坏的问题。那么我们看看具体的代码吧:
package com.kexin.designpatterns.simpleFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AdvancedCarFactory {
public Automobile produceCar(Class<?> assemblyLineName)
{
Automobile autoMoblie = null;
Method produceMethod = null;
Method [] methods = assemblyLineName.getMethods();
for(Method m : methods)
{
if(m.getName().contains("produce"))
{
produceMethod = m;
}
}
try {
autoMoblie = (Automobile) produceMethod.invoke(assemblyLineName.newInstance(),null);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return autoMoblie;
}
}
现在我们看看使用者如何使用这个工厂吧:
package com.kexin.designpatterns.simpleFactory;
public class CarProducer {
public static void main(String[] args)
{
AutomobileFactory factory = AutomobileFactory.getInstance();
Audi audi = (Audi)factory.produceAutomobile("Audi");
audi.showCar();
Benz benz = (Benz)factory.produceAutomobile("Benz");
benz.showCar();
BMW bmw = (BMW)factory.produceAutomobile("BMW");
bmw.showCar();
Benz benz2 = (Benz)(new AdvancedCarFactory().produceCar(BenzFactory.class));
benz2.showCar();
}
}
从最后这段代码我们可以看到使用者完全不必去关心各种类型的汽车到底是如何被生产的,他只需要简单的选择自己需要生产的汽车的类型,然后其他的工作都交给统一管理工厂去处理就可以了。好了我的第一个设计模式就到这里吧。
后续我会继续更新这一系列的blog。(因为之前没有学过UML,所以对设计程序架构这一块实在是不会,看的书上有很多类图,类图可以直接反应一个系统的结构,对于这些模式的类图就只好以后慢慢更新上来了,目前也准备开始慢慢的去学一学UML,现在发现这个东西还真是挺重要的)。好了,废话不多说,我们开始吧,对于blog中写得欠佳,或者有误的地方欢迎大家指正。
工厂模式,顾名思义就是使用一个工厂生产东西。那么我们就要汽车工厂为例。我们使用汽车工厂生产各种不同类型的汽车。工厂模式的主要作用是使用一个统一的工厂去控制生产某大类物品中的各种不同的具体物品,比如使用汽车工厂生产奔驰,奥迪,宝马等等不懂类型的汽车。对于工厂的使用者来说他并不关心汽车是怎么具体的被生产出来的,那么我们就要对汽车工厂的使用者隐藏各种不同类型的汽车的细节,使用者只需要简单的选择自己需要生产何种类型的车,然后拿到被生产出来的物品就可以了。
汽车的种类那么多,生产者没那么多精力去管理那么多的生产线,那么就必须有一个统一的总控制部件来控制不同的生产线来生产各种汽车,这样我们就必须抽象出一个汽车大类,而其他的具体的种类的汽车继承这个大类,然后我们就可以对不同种类的车进行统一的管理,同样不同种类的车应该在自己的生产线上生产出来,启动哪个生产线进行生产就会产出哪种类型的车,这样我们就需要一个管理生产线的总控室。这样各个不同的类之间的关系就可以抽象出来了。
类图(后续再补充)
汽车大类:
package com.kexin.designpatterns.simpleFactory; public abstract class Automobile { /** * 汽车类型 */ String carBrand; /** * 引擎 */ String engine; /** * 汽车框架 */ String carFrame; /** * 汽车轮胎 */ String [] wheels; /** * 显示汽车的一些参数 * 其实这个方法也应该被各个不同的汽车的子类继承的, * 因为不同的汽车需要显示的参数中应该也是有很多不同的。 */ public void showCar() { System.out.println("Automotive Parts:"); System.out.println(this.carBrand); System.out.println(this.carFrame); System.out.println(this.engine); System.out.print("wheels:"); for(String s : this.wheels) { System.out.print(s + " "); } System.out.println(); } }
具体的汽车类:
package com.kexin.designpatterns.simpleFactory; public class Audi extends Automobile{ public Audi() { this.carBrand = "Audi"; this.carFrame = "Audi Frame"; this.engine = "Audi Engine"; this.wheels = new String[4]; this.wheels[0] = "Audi FrontLeft wheel"; this.wheels[1] = "Audi FrontRight wheel"; this.wheels[2] = "Audi BehindLeft wheel"; this.wheels[3] = "Audi BehindRight wheel"; } }
package com.kexin.designpatterns.simpleFactory; public class Benz extends Automobile{ public Benz() { this.carBrand = "Benz"; this.carFrame = "Benz Frame"; this.engine = "Benz Engine"; this.wheels = new String[4]; this.wheels[0] = "Benz FrontLeft wheel"; this.wheels[1] = "Benz FrontRight wheel"; this.wheels[2] = "Benz BehindLeft wheel"; this.wheels[3] = "Benz BehindRight wheel"; } }
package com.kexin.designpatterns.simpleFactory; public class BMW extends Automobile{ public BMW() { this.carBrand = "BMW"; this.carFrame = "BMW Frame"; this.engine = "BMW Engine"; this.wheels = new String[4]; this.wheels[0] = "BMW FrontLeft wheel"; this.wheels[1] = "BMW FrontRight wheel"; this.wheels[2] = "BMW BehindLeft wheel"; this.wheels[3] = "BMW BehindRight wheel"; } }
具体的汽车生产线类:
package com.kexin.designpatterns.simpleFactory; /** * 奥迪工厂 * @author Administrator * */ public class AudiFactory{ private static AudiFactory audiFactory; public Audi produceAudi() { System.out.println("A new Audi is under building..."); Audi audi = new Audi(); System.out.println("completed !"); return audi; } public static AudiFactory getInstance() { if(audiFactory == null) { audiFactory = new AudiFactory(); } return audiFactory; } }
package com.kexin.designpatterns.simpleFactory; /** * 奔驰工厂 * @author Administrator * */ public class BenzFactory { private static BenzFactory benzFactory; public Benz produceBenz() { System.out.println("A new Benz is under building..."); Benz benz = new Benz(); System.out.println("completed !"); return benz; } public static BenzFactory getInstance() { if(benzFactory == null) { benzFactory = new BenzFactory(); } return benzFactory; } }
package com.kexin.designpatterns.simpleFactory; public class BMWFactory { private static BMWFactory bmwFactory; public BMW produceBMW() { System.out.println("A new Benz is under building..."); BMW bmw = new BMW(); System.out.println("completed !"); return bmw; } public static BMWFactory getInstance() { if(bmwFactory == null) { bmwFactory = new BMWFactory(); } return bmwFactory; } }
具体生产线的统一管理类:
package com.kexin.designpatterns.simpleFactory;
/**
* 抽象汽车工厂
* @author Administrator
* 实际上不同的车型,生产的工序中还是有很多的不同点的,所以要让不同的汽车工厂
* 都各自实现这个方法,已完成生产不同种类的汽车的需要
*/
public class AutomobileFactory {
private static AutomobileFactory automobileFactory ;
/**
* 提供不同的工厂名字,决定生产何种类型的车。
* 这种方式,每次有新的类型的汽车生产工厂建立起来后就必须改的这个类。
* @param FactoryName
* @return
*/
public Automobile produceAutomobile(String factoryName)
{
Automobile autoMobile = null;
switch(factoryName)
{
case "Audi":
autoMobile = AudiFactory.getInstance().produceAudi();
break;
case "Benz":
autoMobile = BenzFactory.getInstance().produceBenz();
break;
case "BMW":
autoMobile = BMWFactory.getInstance().produceBMW();
break;
}
return autoMobile;
}
public static AutomobileFactory getInstance()
{
if(automobileFactory == null)
{
automobileFactory = new AutomobileFactory();
}
return automobileFactory;
}
}
从上面的代码我们可以发现这里有一个缺点:如果我们的工程已经投入使用了,而我们这个时候需要新增一条大众汽车生产线,那么我们就必须去修改最后那个统一生产线管理类,这就破坏了软件设计中的开放闭合原则:开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。
放封闭原则,其核心的思想是:
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。因此,开放封闭原则主要体现在两个方面: 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。 对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。这就是简单工厂的一个缺点。为了解决这个问题我对统一工厂管理类进行了一点改进。利用反射(这是对编程语言有依赖的,现在有些面向对象的编程语言并不支持反射,但是java支持),我们在统一管理工厂里面把具体生产线类的Class对象作为参数传进去,通过这个对象来动态生成这个生产线类的实例,然后使用这个实例调用自己的生产方法来生产汽车。这样当有新的汽车生产线加进来的时候我们只需要传入这个生产线的Class对象就可以了(前提是你必须有这种新汽车结构模板并且已经为它搭建好了生产线)而不需要去修改统一管理工厂类了,而传入的参数是可以有工厂的使用者决定的,这就解决了开发闭合原则被破坏的问题。那么我们看看具体的代码吧:
package com.kexin.designpatterns.simpleFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AdvancedCarFactory {
public Automobile produceCar(Class<?> assemblyLineName)
{
Automobile autoMoblie = null;
Method produceMethod = null;
Method [] methods = assemblyLineName.getMethods();
for(Method m : methods)
{
if(m.getName().contains("produce"))
{
produceMethod = m;
}
}
try {
autoMoblie = (Automobile) produceMethod.invoke(assemblyLineName.newInstance(),null);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return autoMoblie;
}
}
现在我们看看使用者如何使用这个工厂吧:
package com.kexin.designpatterns.simpleFactory;
public class CarProducer {
public static void main(String[] args)
{
AutomobileFactory factory = AutomobileFactory.getInstance();
Audi audi = (Audi)factory.produceAutomobile("Audi");
audi.showCar();
Benz benz = (Benz)factory.produceAutomobile("Benz");
benz.showCar();
BMW bmw = (BMW)factory.produceAutomobile("BMW");
bmw.showCar();
Benz benz2 = (Benz)(new AdvancedCarFactory().produceCar(BenzFactory.class));
benz2.showCar();
}
}
从最后这段代码我们可以看到使用者完全不必去关心各种类型的汽车到底是如何被生产的,他只需要简单的选择自己需要生产的汽车的类型,然后其他的工作都交给统一管理工厂去处理就可以了。好了我的第一个设计模式就到这里吧。
相关文章推荐
- 设计模式学习之路——简单工厂模式
- 菜鸟学习设计模式之路——简单工厂模式
- [设计模式学习]设计模式学习之简单工厂模式
- 设计模式学习之简单工厂模式
- 设计模式的学习之路--模板方法设计模式
- 设计模式学习之工厂模式(简单工厂模式)
- 教为学:设计模式学习之路(一):设计模式的基本设计原则
- 设计模式学习笔记——简单工厂模式
- 我的设计模式学习之路6(门面模式)
- Java研究之学习设计模式-简单工厂模式详解
- 【设计模式】简单工厂模式学习笔记
- 设计模式的学习之路 --- 第一站(模板模式)
- 设计模式之简单工厂模式,工厂模式,抽象工厂模式学习总结
- 设计模式的学习之路,工厂模式加桥模式
- 我的设计模式学习之路一——单例模式
- 设计模式---简单工厂模式(学习笔记)
- 设计模式学习之路 - 适配器模式 - 接口转换器
- 设计模式学习之路-原型模式
- 多线程学习之路-学习master-worker设计模式
- java设计模式学习之简单工厂模式