说明:
- 介绍常用的设计模式,针对每个设计模式增加实例进行说明。
- 开源是方便自己进行查看。
基本概念:white_check_mark:
- 面向对象编程具有三个有点:封装,多态,可继承
- 工厂:用一个单独的类A来创建要实例化的类。这个类A称为工厂。
- UML类图
实例应用
- 使用面向对象的方式编写一个计算器
- 除完成基本的加减乘除运算,可以方便添加开方等操作运算
实现
- 建立一个操作类
Operation
,添加两个基本属性;并将返回结果方法getResult
定义为抽象方法。 - 针对不同的运算操作各自新建一个类;并继承
Operation
类,对getResult
方法体进行具体实现 - 新建一个工厂类,该工厂返回一个
Operation
UML类图理解
-
类图分三层,第一层显示类的名称,如果是抽象类,则就用斜体显示。第二层是类的特性,通常就是字段和属性。第三层是类的操作,通常是方法或行为。
-
‘+’表示public,‘-’表示private,‘#’表示protected
-
<<interface>>表示接口。接口还有另一种表示方法,俗称棒棒糖表示法
-
空心△+实线表示继承
-
实线箭头表示关联。如企鹅与气候有关,那么企鹅类中可以包含气候对象
-
空心◇+实线箭头表示拥有。如雁群包含大雁
-
实心◇+实线箭头表示合成。如翅膀组合成了鸟
-
虚线箭头表示依赖关系
工厂方法模式与简单工厂模式有所区别
- 工厂方法模式针对产品和工厂都各自有一个抽象接口
- 所有的具体工厂和具体产品都实现上述的接口
- 在客户端创建具体产品对象时,使用具体的工厂
应用
- 有两种不同的人群(甚至更多的人群)在进行学雷锋活动。
- 通过指定不同的工厂方法获得不同的对象
实现
-
建立
LeiFeng
作为抽象产品,所有的具体产品类都是该类的子类 -
建立抽象工厂
Factory
,只负责生产抽象产品LeiFeng
对象 -
针对具体的产品类建立对应的工厂。如
VolunteerFactory
专用于生产Volunteer
对象 -
进行测试
点评
- 工厂方法模式相较于简单工厂方法模式,设立了具体的工厂方法专用于负责生产具体产品对象;虽然在代码量上有一定增加,但是其保证了开放-封闭原则。而简单工厂方法模式,通过一个简单工厂,客户端获得对象时需要给工厂传入一个参数(用来帮助工厂判断生产那个对象),看似没有问题,但实际有大问题
- 当工厂需要生产其他具体类对象时,需要针对简单工厂中的
switch
语句进行修改,添加case。这违背了开放-封闭原则(即开放拓展,但不开放修改) - 使用工厂方法模式,客户端如需要改变对象时,只需要修改一行代码即可(修改调用的具体工厂方法)
- 当工厂需要生产其他具体类对象时,需要针对简单工厂中的
策略模式与工厂模式
- 策略模式针对的是不同的算法和实现。
- 工厂模式针对的是对象层面,可以将两者结合起来使用。
- 通过不同的策略(使用文字描述策略)产生不同的处理对象。
策略模式
实际应用
- 根据要求,完成最简单的商场结算计费。
- 考虑到商场不同的促销价格,如打折促销,满减促销
- 对比工厂模式,简单策略模式,策略模式与简单工厂结合
实现
- 建立
CashSuper
类,用来描述现金收费;在其中添加抽象方法acceptCash - 分别对应三种策略建立
CashNormal|CashRebate|CashReturn
类,用来描述无促销,打折,满减优惠 - 建立
CashContext
类,用来维护不同的策略。根据传入的策略字符串返回执行对应策略的对象 - 建立客户端,需要指定原始金额,促销策略;得到对应策略的对象执行方法,输出需要支付的金额
点评:white_check_mark:
-
改进后的CashContext承担了策略和工厂的作用。客户只需要指定不同策略对应的对象
CashContext
;只需要传递一个String type
,用来描述使用何种策略。简单工厂不一定是一个单独的类 -
改进前的CashContext只负责策略,执行不同的促销策略需要客户来指定所使用的类。需要知道
CashContext对象
和CashNormal|CashReturn|CashRebate
.(这样其实就相当于返回到最原始的方式了) -
结合工厂模式,易出现针对不同的促销方案设计不同的之类的情况。应该注意到,打折和满减可视为两种基本的方案,剩下的就是
折扣数
和满减门槛
的问题。(面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类) -
只有两种基本的促销方案,可以考虑使用策略模式;具体的不同促销方案都是在这两种基本下的具体实现。
-
使用策略模式需要注意维护的是哪个对象,并与工厂模式产生的对象加以区分
优点
- 装饰类和被装饰类可以独立发展,不会相互耦合。
- 装饰模式可以动态地拓展一个类的功能
使用场景
- 拓展一个类的功能
- 动态增加功能,动态取消
装饰模式图解
应用
- 对一个
Person
对象的功能进行增强 - 对
Person
类的服饰进行增强。Person
可以穿不同的衣服
实现
-
创建一个
Component
接口,作为被增强的类的抽象 -
创建一个
Person
类,作为具体的被增强的类。(可以理解为该类是Component的子类) -
创建
Finery
类,作为增强类的抽象类。如果要对Person
类进行增强,可以创建该子类 -
创建
Tshirts
类,作为具体的增强类。该类继承了Finery
类 -
创建测试用例
点评
- 在实际使用中,可以根据需要对增强类和被增强类进行处理。确定是否需要抽象出父类。
- 在本实例应用中,存在逻辑混乱的问题。后续修改:x:
概念
- 为其他对象提供一种代理以控制对这个对象的访问
- 远程代理。为一个对象在不同的地址空间提供局部代表。起到隐藏对象真实地址的效果
- 虚拟代理。根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真是对象。浏览器当中是用代理模式来优化下载的
- 安全代理用来控制真是对象访问时的权限
应用场景
Persuit
通过中间人Proxy
向SchoolGirl
送礼物等操作。
实现
- 建一个被代理的类
Persuit
。在其中包含执行具体行为的方法 - 建一个代理类
Proxy
。在代理类中对传入的参数进行处理(本例子中就是SchoolGirl
)
点评
- 代理类最常见的是Spring框架当中,其中应用为对代理类进行功能增强。但是在本例中只是简单的代理。对类的行为进行代理(送礼物等行为)
- 有一个奇怪的行为:
proxy
是对GiveGift
接口进行实现(没有写具体的方法体),在传入对象的时候针对一个属性对象赋值。然后就可以执行该对象中的方法了。对Persuit
类没有特别的处理,但是最终却实现了对其方法的应用。 - 理解还不充分:x: