目录
- 0. 学习目标
- 0.1 软件设计模式
- 0.2 软件体系结构
- 软件设计模式
- 0. 软件设计原则
- 设计模式的分类
- 创建型软件设计模式
- 一、工厂模式
- 工厂方法与抽象工厂模式
- 1.简单工厂方法模式(开闭原则)
- 优缺点
- 适用场景
- 实例一:简单电视机工厂
- 2.工厂方法模式
- 优缺点
- 适用场景
- 实例一:汽车保险管理程序
- 实例二:电视机工厂
- 3. 简单工厂模式与工厂方法模式的区别
- 4. 抽象工厂模式
- 产品等级概念(继承同一东西)与产品族(同一个工厂下的不同继承不同东西)
- 优缺点
- 适用场景
- 实例一
- 实例一:房屋销售查询系统
- 实例二:电器工厂
- 抽象工厂模式的可拓展性(两种情况开闭原则)
- 5. 小结
- 6. 课程作业
- 简答题
- 画图题
0. 学习目标
0.1 软件设计模式
0.2 软件体系结构
软件设计模式
0. 软件设计原则
开闭原则
设计模式的分类
根据其目的(模式是用来做什么的),面向对象的领域的设计模式可分为创建型(Creational),结构型(Structural)和行为型(Behavioral) 三种:
创建型模式主要用于创建对象
结构型模式主要用于处理类或对象的组合
行为型模式主要用于描述对类或对象怎样交互和怎样分配职责
创建型软件设计模式
创建型软件设计模式是为了将创建对象的责任委托给某个特殊的类,所以注意被创建的对象和谁创建,怎样创建,增强代码的灵活性
创建和使用分离
创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。
模式包括:
1.模式的名称
2.模式的目的,即要解决的问题
3.实现方法
4.为实现该模式必须考虑的限制和约束因素
一、工厂模式
工厂方法与抽象工厂模式
1.简单工厂方法模式(开闭原则)
简单工厂模式:又称为静态工厂方法模式。
在简单工厂模式中,可以根据参数的不同返回不同类的实例。
简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
Creator cr = new Creator();
Product p = cr.factory(“option”);
p.Operation();
优缺点
优点
- 实现了对责任的分割,它提供了专门的工厂类用于创建对象
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类
缺点
- 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响
- 增加系统中类的个数
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时
- 工厂角色无法形成基于继承的等级结构
简单工厂模式最大的缺点就是当有新产品要加入到系统中时,必须修改工厂类,加入必要的处理逻辑,这违背了“开闭原则”
并且要是工厂类失效,整个系统都失效了
类的个数很多
适用场景
所以一般只有在对应的类少,以及客户端只需要提供参数就得到对应的对象
实例一:简单电视机工厂
如果需要增加新的TV,则需要修改工厂类的传参的条件
2.工厂方法模式
将简单工厂方法中单一的工厂类改写为一个层次类
对应简单工厂模式的工厂角色无法形成基于继承的等级结构
Creator cr = null;
if ( x = a ) cr = new CreatorA();
else
cr = new CreatorB();
Product p = cr.factory();
在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做
工厂方法模式退化后可以演变成简单工厂模式
优缺点
优点:
- 用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名(因为一个工厂创建一个产品)
- 工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部
- 在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。
缺点:
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
适用场景
- 一个类不知道它所需要的对象的类
- 一个类通过其子类来指定创建哪个对象(子类指定创建的对象)
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定
实例一:汽车保险管理程序
PolicyProducer pp = null;
if ( x = “BodyPolicy” ) pp = new BodyPolicy();
else if ( x = “Collision” ) pp = new CollPolicy();
else if ( x = “PersonInjure” ) pp = new PersonPolicy();
else if ( x = “Property” ) pp = new PropPolicy();
else if ( x = “Comprehensive” ) pp = new ComPolicy();
AutoInsurance ai = pp.getInsurObj();
实例二:电视机工厂
3. 简单工厂模式与工厂方法模式的区别
- 两个模式的中心不同。
- 是否支持开闭原则。
- 创建对象逻辑判断的位置。
简单工厂模式的中心为一个实的工厂类,工厂方法模式的中心为抽象工厂或者接口
简单工厂模式不支持开闭原则,而工厂模式支持
简单工厂模式中,必要的创建对象的逻辑判断包含在工厂类中(实例一:汽车保险管理程序),在工厂方法模式中,工厂类不必包含创建对象的逻辑判断
4. 抽象工厂模式
但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
产品等级概念(继承同一东西)与产品族(同一个工厂下的不同继承不同东西)
优缺点
优点
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。
- 所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
- 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
缺点
- 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
- 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)
适用场景
实例一
Creator cr = null;
if ( x ==a ) cr = new ConcreteCreatorA();
else if ( x == b ) cr = new ConcreteCreatorB();
if ( y = “ManTie” ) ManTie mt = cr.factoryA();
else if ( y = “WomanTie” ) WomanTie wt = cr.factoryA();
else if ( y = “ManShoes” ) ManShoes ms = cr.factoryB();
else if ( y = “WomanShoes” ) WomanShoes ws = cr.factoryB();
else if ( y = “ManSuit” ) ManSuit msi = cr.factoryC();
else if ( y = “WomanSuit” ) WomanSuit wsi = cr.factoryC():
实例一:房屋销售查询系统
BuildingFactory bf = BuildingFactory.getBuildingFactory(“option”);
if ( x == “House” ) House hs = bf.getHouse();
else if ( x == “Cando” ) Cando cd = bf.getCando();
实例二:电器工厂
抽象工厂模式的可拓展性(两种情况开闭原则)
增加一个新的产品族,新的品牌的产品,只就需要一个新的具体工厂,不需要修改工厂接口,符合开闭原则
增加已有产品族的产品,需要修改具体的工厂和工厂接口,不符合开闭原则
不能横向扩展,只能纵向扩展,就是只能从冰箱A扩展到冰箱B(多一个品牌),不能扩展出汽车A
例如原来有两家公司A和B生产电视和冰箱,现在增加一个公司C也生产电视和冰箱则符合开闭原则
但如果是让原来的A和B新增加生产空调,则不符合开闭原则
5. 小结
抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。
抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。
6. 课程作业
简答题
1.简单工厂模式一般不符合开闭原则。在简单工厂模式中,如果要增加一个新产品类,相应地在工厂类中也要增加一个条件语句,用于创建新的产品类的对象。也就是说,必须修改工厂类的源代码。
2.工厂方法模式和抽象工厂模式符合开闭原则。因为在工厂方法模式和抽象工厂模式中,无需修改或者重新编译已经存在的代码,就可以添加新的产品类。
3.开闭模式是指对扩展开放,对修改关闭,说的更通俗点,就是说开发了一个软件,应该可以对它进行功能扩展(开放),而在进行这些扩展的时候,不需要对原来的程序进行修改(关闭)。
-
工厂方法模式符合开闭原则,因为它通过定义一个抽象的工厂接口和多个具体的工厂类,每个具体工厂类都实现了工厂接口,用于创建一类产品。当需要新增一种产品时,只需要添加一个对应的具体工厂类,而不需要修改已有的代码。这样做的好处是,在不修改现有代码的前提下,可以灵活地扩展系统,符合开闭原则的要求。
-
抽象工厂模式也符合开闭原则,它通过定义一个抽象的工厂接口和多个具体的工厂类,每个具体工厂类都负责创建一组相关的产品。当需要新增一组相关产品时,只需要添加对应的具体工厂类和产品类,而不需要修改已有的代码。这样可以保持系统的灵活性和可扩展性,符合开闭原则。
倘若要是增加一组产品族产品,就不符合开闭原则,需要修改原有代码 -
然而,简单工厂方法模式并不符合开闭原则。在简单工厂方法模式中,只有一个具体的工厂类负责创建所有的产品,根据不同的参数或条件来决定创建哪种产品。当需要新增一种产品时,需要修改具体工厂类的代码,违反了开闭原则。因此,在简单工厂方法模式下,开闭原则不成立。
画图题
在图2.17游戏软件设计中,游戏工厂(SlowGameFactory)类负责创建低级战士(SlowFighter)对象与低级怪物(SlowMonster)对象,并且将创建完的对象以其超类类型返回给用户界面客户端(ClientGUI)对象。然后,用户界面客户端(ClientGUI)对象将操纵低级战士(SlowFighter)对象与低级怪物(SlowMonster)对象,使得它们互相打斗。问题与任务:1、上述设计使用了什么设计模式?2、请在以上设计类图中添加4个新的类包括中级战士(MedFighter)、高级战士(SuperFighter)、中级怪物(MedMonster)和高级怪物(SuperMonster),使得中级战士(MedFighter)对象与中级怪物(MedMonster)对象是由一个抽象工厂类创建;高级战士(SuperFighter)对象与高级怪物(SuperMonster)对象由一个抽象工厂类创建,绘制新设计类图;3、除了以上添加的4个类以外,在以上类图中还应该添加什么类?4、描述新的设计类图;5、明确说明新设计的优点。
1、上述设计使用了抽象工厂设计模式
2、
3、SuperGameFactory和MedGameFactory
4、多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品。
5、工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。