北京学校网站建设,发新闻稿平台,tp网站开发,东莞网站制作推广公司在经济学领域中#xff0c;其主要研究对象(商品)之间根据消费依存关系可分为互补商品或替代商品#xff0c;其中#xff0c;互补商品如汽车与汽油、自行车与自行车胎、大饼和香肠、开水和泡面等。在面向对象的代码世界中#xff0c;不同对象之间也存在这种类似相互依赖的关…在经济学领域中其主要研究对象(商品)之间根据消费依存关系可分为互补商品或替代商品其中互补商品如汽车与汽油、自行车与自行车胎、大饼和香肠、开水和泡面等。在面向对象的代码世界中不同对象之间也存在这种类似相互依赖的关系【注这种关系非指定为上面互补关系】比如特斯拉汽车与新能源、奔驰汽车与92汽油、拖拉机与柴油这种依赖关系是具有明显的依赖关系的。这意味着如果用户客户端获取的汽车对象种类不同也意味着其所需要的能源种类也存在不同。思考这样一个问题不同对象之间的依赖关系应该由谁去维护(负责)
由客户端维护客户端不适合维护这种依赖关系。如果目标对象发生升级改造可能会使得这种依赖关系改变改变就需要所有上游跟随改动不利于系统稳定性。由目标创建对象维护有的同学可能认为能源应该是汽车的属性因此应该由目标对象维护合适。这是由于上面的例子的特殊性(整体与部分)比如左车门和右车门的个数这种平级对象约束就无法由目标对象维护了。
那我们有没有可能添加一个中间层来负责这种对象依赖关系呢答案就是抽象工厂模式。
一、抽象工厂模式概念
区别于前面文章讲解的用于封装创建过程的工厂方法模式抽象工厂模式更关注于创建的不同对象之间的约束关系。因此我们将这些不同对象的创建过程及其之间的约束关系封装于工厂中客户端仅需要使用该工厂去创建对应需要的对象即可不需要感知其间的约束关系。这些不同对象在大多数的参考资料中被称之为产品族。这也意味着产品族有多少个对象那么工厂就会有几个创建对象的方法。 如何理解抽象抽象我们通常等同于不可实例化。但是我们要彻底理解抽象的概念才能理解抽象工厂。在Java中的不可实例化对象实际上是个狭隘理解抽象应该理解为区别于具体的概念化的东西。如上述中不同对象之间的约束关系这就是抽象化的概念进而负责这种关系的工厂也就是抽象工厂了。抽象工厂并非是说抽象工厂模式是实现上使用了抽象类工厂方法模式也有抽象类这是依赖倒置原则决定的。 对于抽象工厂模式理解了“产品族之间的约束关系”“抽象含义”基本就无难点了。抽象工厂模式定义如下 为创建一组相关或相互依赖的对象提供一个接口而且无须指定他们的具体类。 前半句就指明了上述的两个概念。后面半句说的是具体产品族中各个对象的具体实现类由具体工厂决定。
二、应用实践
抽象工厂模式相对来说还是有一点理解难度的本章节将采用一个合适的案例来讲解抽象工厂模式。 案例背景完成实现文本编辑器的创建和输入法创建在不同操作平台(Windows、Mac)上的实现。我们都知道不同操作系统的文本编辑器必然需要选用合适的输入法才能正常工作使用。因此在系统中会存在不同操作平台下的文本编辑器对象和输入法对象在创建这些对象的时候一定要处理好他们之间的约束关系否则就不能正常工作。 具体实现使用抽象工厂方法模式来创建文本编辑器对象和输入法对象且这种约束关系由工厂来维护。代码如下 ① 产品接口
public interface TextEditor {void open();void save();
}public interface InputMethod {void type();void select();
}② 产品具体实现类 Win平台
public class WindowsTextEditor implements TextEditor {Overridepublic void open() {System.out.println(Win文本编辑器: Open);}Overridepublic void save() {System.out.println(Win文本编辑器: Save);}
}public class WindowsInputMethod implements InputMethod {Overridepublic void type() {System.out.println(Win输入法: Type);}Overridepublic void select() {System.out.println(Win输入法: Select);}
}Mac平台
public class MacTextEditor implements TextEditor {Overridepublic void open() {System.out.println(Mac文本编辑器: Open);}Overridepublic void save() {System.out.println(Mac文本编辑器: Save);}
}public class MacInputMethod implements InputMethod {Overridepublic void type() {System.out.println(Mac输入法: Type);}Overridepublic void select() {System.out.println(Mac输入法: Select);}
}③ 工厂接口
public interface Factory {TextEditor createTextEditor();InputMethod createInputMethod();
}④ 具体实现工厂 Win平台
public class WindowsFactory implements Factory{Overridepublic TextEditor createTextEditor() {return new WindowsTextEditor();}Overridepublic InputMethod createInputMethod() {return new WindowsInputMethod();}
}Mac平台
public class MacFactory implements Factory{Overridepublic TextEditor createTextEditor() {return new MacTextEditor();}Overridepublic InputMethod createInputMethod() {return new MacInputMethod();}
}⑤ 客户端
public class Client {public static void main(String[] args) {// 根据当前操作平台选择工厂类Factory factory;String os System.getProperty(os.name).toLowerCase();if (os.contains(windows)) {factory new WindowsFactory();} else if (os.contains(mac)) {factory new MacFactory();} else {throw new RuntimeException(不在可支持的系统类型范围内);}// 创建文本编辑器和输入法【客户端感知不到不同系统有不同的输入法】TextEditor textEditor factory.createTextEditor();InputMethod inputMethod factory.createInputMethod();// 使用文本编辑器和输入法textEditor.open();inputMethod.type();}
}代码及类图如上对于客户端来说如果是Win平台就使用WindowsFactory来获取编辑器和输入法如果是Mac平台就使用MacFactory来获取编辑器和输入法。客户端不会感知到编辑器和输入法之间的约束关系直接使用即可。 在代码可扩展性方面如果后续增加Linux平台产品族仅需要增加对应的LinuxTesxEditor、LinuxInputMethod具体产品类以及对应的抽象工厂-LinuxFactory即可不影响原有业务逻辑符合开闭原则。【说明】在一些参考资料中认为虽然产品族的扩展很简单但是产品族内对象种类发生增加需要所有产品族以及工厂改动因此不符合开闭原则。个人认为不应该这么理解首先对于开闭原则之前说过其核心是不改变原有逻辑即是扩展改变原有逻辑即是改变(应当对其关闭)。因此增加方法、增加属性不改变原有逻辑也并不定算是破坏了开闭原则。再者如果增加属性方法可能会破坏了接口隔离原则这时就要思考要不要增加产品族的对象符合业务逻辑那就应该加入并且上游也应当参与修改(产品本身已发生改变)。不符合业务逻辑是否应该属于另外一套产品族呢另外一套产品族是能满足开闭原则的。 抽象工厂模式优点
满足具有约束关系的产品族对象的创建进一步避免客户端与产品耦合性满足开闭原则
抽象工厂模式缺点
代码逻辑复杂且类会出现激增。 抽象工厂模式不是用于解决工厂类泛滥问题的方案