抽象工厂模式.docx
《抽象工厂模式.docx》由会员分享,可在线阅读,更多相关《抽象工厂模式.docx(33页珍藏版)》请在冰豆网上搜索。
抽象工厂模式
抽象工厂模式(3.1)
镇楼
在某些书中使用了二维图说明抽象工厂模式,很好,但是yqj2065不喜欢他们的产品族/产品等级,改成品牌/产品类型。
抽象工厂模式(abstractfactorypattern)较工厂方法模式强大之处,是一个工厂能够创建多个配套的产品。
日常生活中,抽象工厂模式比比皆是。
例如服装厂可以生产配套的上衣/Tops、下装/Bottoms。
电器公司如美的、海尔可以生产其品牌的冰箱、空调、电视机等。
抽象工厂模式的特点就是工厂接口中有两个以上的工厂方法。
[java] viewplaincopy
1.例程 2-6 品牌公司
2.package creational.factory.abstractFactory;
3.public class NikeFactory implements IClothingFactory{
4. @Override public Tops getTops(){
5. return new NikeTops();
6. }
7. @Override public Bottoms getBottoms(){
8. return new NikeBottoms();
9. }
10.}
抽象工厂模式概念简单,但是编写演示程序是至少要编写10个类(含Client)。
如图所示。
显然的,NikeFactory只会生产NikeTops和NikeBottoms,毕竟品牌公司不是山寨或贴牌公司。
(yqj2065在后面考虑山寨问题)
[java] viewplaincopy
1.package creational.factory.abstractFactory;
2.public class Client{
3. public static void test(){
4. IClothingFactory f =(IClothingFactory)tool.God.create("2-6-Factory");
5. Tops tops = f.getTops();
6. Bottoms bt =f.getBottoms();
7. System.out.println(tops.getName());
8. System.out.println(bt.getName() );
9. }
10.}
抽象工厂模式包含4个角色。
抽象工厂角色,如IClothingFactory;具体工厂角色,前者的子类型;抽象产品角色,如Tops和Bottoms;而具体产品角色,是抽象产品角色的子类型。
从Client的角度看,抽象工厂模式下,通过配置文件指定IClothingFactory,从而获得其生产的上衣/Tops,可以再指定其他的厂家,获得其生产裤子/Bottoms;Client仅仅依赖于抽象工厂角色和抽象产品角色;避免代码中的newNikeTops()和newAdidasBottoms。
2.扩展性
IClothingFactory的子类,可以按照需要增添,符合OCP。
另一方面,假设现在的服装厂/IClothingFactory除了生产配套的上衣、裤子外,还生产鞋子/Shoe。
IClothingFactory中需要添加
publicBottomsgetShoe();
Java8之前,接口不能升级。
如果定义了接口,将接口送给客户程序员使用,这时定义的接口就不能修改。
因为在接口中添加一个方法,会导致老版本接口的所有实现类的中断。
如今,在IClothingFactory广泛使用而且非常需要与时俱进地添加getShoe()时,Java8的默认方法(defendermethods,Virtualextensionmethods)如同神奇的后悔药。
[java] viewplaincopy
1.例程 2-7 默认方法
2.package creational.factory.abstractFactory;
3.public interface IClothingFactory{
4. public Tops getTops();
5. public Bottoms getBottoms();
6. default public Shoe getShoe(){
7. return null;
8. }
9.}
10.class Client{
11. public static void test(){
12. IClothingFactory f =(IClothingFactory)tool.God.create("2-6-Factory-Nike");
13. //f =(IClothingFactory)tool.God.create("2-6-Factory-Ad");
14. Shoe shoe =f.getShoe();
15. System.out.println(shoe.getName() );
16. }
17.}
NikeFactory改写了getShoe(),测试代码中Client可以正常获得Shoe对象;如果指定的具体工厂没有改写了getShoe(),则Shoe对象为null。
接口中添加默认方法,对于没有改写该默认方法的子类,都是一种退化继承——如同鸵鸟是鸟,违反LSP因而违反OCP。
接口中添加默认方法,保证以前的代码能够正常运行——因为以前的代码不可能知道也不存在使用getShoe(),因而保证了向前兼容。
但是,编写新代码时就必须注意,IClothingFactory有方法getShoe(),但是并非其实现类都给出有效的实现。
你凭什么认为IClothingFactory的实例都能够生产鞋子呢?
工厂方法模式(3.3)
工厂方法模式(factorymethodpattern)从2方面认识。
编程技巧:
这是对参数化工厂方法加以改进的经典技术,以多态来重构if-else、switch-case等分支结构。
设计思路:
你一定要注意,工厂方法模式中Client关注的不是的产品(所以静态工厂中Door的例子,不适合),Client关注的是工厂!
1.以多态来重构分支结构
静态工厂的缺点是分支结构,需要增添新的分支时,程序不符合OCP。
[java] viewplaincopy
1.package creational.factory;
2.public class DoorFactory{
3. public static Door getObject(String typeName) {//int ID
4. if(typeName.equals("D1")){
5. return new D1();
6. }else if(typeName.equals("D2")){
7. return new D2();
8. }else{
9. return null;
10. }
11. }
12.}
13.
14.package creational.factory;
15.public class Hand{
16. static Door d = null;
17. public static void test(){
18. d = DoorFactory.getObject("D2") ;
19. d.m();
20. }
21.}
在不使用配置文件和反射机制的情况下,
[java] viewplaincopy
1.interface IDoorFactory {
2. public Door createDoor();
3.}
4.
5.class D1Factory implements IDoorFactory {
6. public D1 createDoor() {
7. return new D1();
8. }
9.}//D2Factory 略
10.
11.
12.public class Client {
13. public static void main(String[] args) {
14. IDoorFactory factory = new D1Factory();
15. Door door= factory.createDoor();//生产D1
16. door.m();
17. }
18.}
将工厂类泛化成抽象类型,以其子类多态地创建不同的产品如Door的子类。
它体现了一种非常重要的思考方式——以多态来重构if-else或switch-case结构。
从重构分支结构的角度看,策略模式与[2.1.3工厂方法模式(3.3)]和[4.2状态模式(5.8)]是三胞胎。
2.颠倒黑白
上面例子中Hand采用工厂方法模式并不令人信服。
Hand避免了依赖Door的具体子类D1、D2等,却变成了依赖具体的D1Factory、D2Factory。
通过依赖注入,可以使得Hand仅仅依赖Factory,但是,这样做不如直接通过依赖注入让Hand依赖抽象类型Door。
编程实践中,通常工厂是Client关注的主体,而工厂生产的产品被Client所忽视。
例如Client开车ICar,不管什么车Client都可以开。
现在,Car要找它的4S店/I4S,Client会关注各种4S店吗?
[java] viewplaincopy
1.interface ICar{ //工厂接口
2. public I4S get4S();//管你是那个4S店
3. public void move();
4.}
5.class BBCar implements ICar{
6. public I4S get4S() {
7. return new BB4S();
8. }
9.
10. public void move(){
11. System.out.println("BBCar move");
12. }
13.}//QQCar 略
14.
15.interface I4S{
16. void doShomthing();
17.}//实现类略
18.public class Client{
19. public static void main(String[] args) {