人生倒计时
- 今日已经过去小时
- 这周已经过去天
- 本月已经过去天
- 今年已经过去个月
一个设计模式( )是一组反复使用的、为大多数人所知的、分类分类的、代码设计经验的总结。设计模式用于可重用代码,使代码更容易被他人理解,并确保代码的可靠性。
就设计模式的类型而言,简单工厂模式是一种创建模式,也称为静态工厂方法( )模式,但它不是 23 GOF 设计模式之一。简单的工厂模式是工厂对象决定创建产品类的哪个实例。简单工厂模式是工厂模式家族中最简单、最实用的模式。可以理解为不同工厂模式的特殊实现。学习这种模式可以为以后的许多中间模式奠定基础。
4.1 设计模式概述
一个设计模式( )是一组反复使用的、为大多数人所知的、分类分类的、代码设计经验的总结。设计模式用于可重用代码,使代码更容易被他人理解,并确保代码的可靠性。
毫无疑问,设计模式对自己、他人和系统都是双赢的。设计模式使编码真正成为工程。设计模式是软件工程的基石,就像建筑物的砖块一样。
GoF 的“设计模式”是第一次将设计模式提升到理论层面并对其进行标准化。本书提出了 23 种基本的设计模式。此后,在可重用的面向对象软件的开发过程中,大量新的设计模式不断涌现。
4.2、设计模式和框架
现在,可重用的面向对象软件系统一般分为三类:应用工具箱和框架(),我们通常开发的具体软件就是应用; Java API 属于工具箱;框架是一组协作类,它们构成了特定类软件的可重用设计。 EJB() 是一个用于企业计算的 Java 框架。
框架通常会定义应用系统的整体结构、类与对象之间的关系等设计参数,以便具体的应用实现者可以专注于应用本身的具体细节。该框架主要记录软件应用程序中常见的设计决策。框架强调设计重用,因此框架设计中必须使用设计模式。
此外,设计模式有助于理解框架的结构。成熟的框架通常使用多种设计模式。如果你熟悉这些设计模式,毫无疑问你会很快掌握框架的结构。我们普通开发者如果突然接触到其他框架,会发现学习和掌握特别困难。那么,首先掌握设计模式无疑将为您提供分析 EJB 或 J2EE 系统的强大工具。
4.3、设计模式的原则
近年来,大家都在关注设计模式。那么,我们到底为什么要使用设计模式呢?为什么这么多设计模式都是这样设计的?老实说,我之前并没有真正想通。光是看到大家喝一口“”,心里就有些空荡荡的。于是买了这本书的设计模式,结果看不懂:我看的时候好像明白了,但看了一会就忘记了。可能是我比较“笨” :)) 最近有点感悟。 《寂寞的音乐不如大家的音乐》,分享给大家,希望大家多多指教!
为什么提倡“”?根本原因是重用代码并提高可维护性。那么如何实现代码复用呢? OO界有几个前辈的原则:“开闭”原则(Open)、里氏替换原则、综合复用原则。设计模式就是为了实现这些原则,从而达到代码复用和增加可维护性的目的。
4.3.1、“开闭”原则
这个原则是由“迈耶”提出的。原文是:“为 开放,但为”。也就是说,模块应该对扩展开放,对修改关闭。模块应尽量在不修改原始(“原始”,指原始代码)代码的情况下进行扩展。那么如何扩展呢?看一下工厂模式“”:假设中关村有个卖盗版光盘和原片的男孩,我们为他设计了一个“CD销售管理软件”。我们首先要设计一个“CD”界面。如图:
[前]
||
|光盘|
||
|+卖出()|
| |
||[/pre]
盗版光盘和原始电影是其子类别。孩子使用“”来管理这些光盘。代码是:
里{
CD(java/lang/.java.html" =""> 名称){
(CD)java/lang/Class.java.html"="">Class.(name).();
}
}
有人要买盗版盘,怎么办?
班上的孩子{
void main(java/lang/.java.html"="">[] args){
CD d=.("盗版光盘");
CD.Sell();
}
}
如果有一天,这孩子的良心发现并开始销售正版软件。没关系,我们只需要创建另一个“CD”子类,“正版软件”。无需修改原有结构和代码。这个怎么样?用于扩展开发,关闭修改。 “开闭原则”
工厂模式是对特定产品的扩展。有些项目可能需要更多的可扩展性。扩展这个“工厂”,就变成了“抽象工厂模式”。
4.3.2、课替换原则
里氏替换原则是由“”提出的。如果调用父类,那么子类也可以完全运行。例如:
CD d=新盗版光盘();
d.sell();
现在把“ disk”类改成“”类,没问题,完全可以运行。 Java 编译器检查程序是否符合 替换原则。还记得java继承的一个原理吗?子类方法的访问权限不能小于父类对应方法的访问权限。比如“CD”中的“sell”访问权限是“”,那么“盗版”和“猫片”中的“sell”方法不能为OR,编译无法通过。为什么一定要这样?你认为:如果“盗版”的“卖”方法是。那么下面的代码就不能执行了:
CD d=新盗版光盘();
d.sell();
可以说,里氏替换原则是继承和重用的基础。
4.3.3、综合复用原理
意思是用更少的继承和更多的组合关系来实现。我曾经写过这样的程序:有几个类需要处理数据库,所以我写了一个对数据库进行操作的类,然后所有其他处理数据库的类都继承这个。结果我修改了数据库操作类的一个方法,每个类都需要改。 “一毛一动全身”!面向对象是将波动限制在尽可能小的范围内。
在 Java 中,尽量专注于编程,而不是实现类。这样,更改子类不会影响调用其方法的代码。让每个班级尽量少接触别人,“不和陌生人说话”。如此一来,城门之火,便不会给池宇带来灾难。可扩展性和可维护性有待提高
了解这些原则,看看设计模式,看看如何在具体问题上实现这些原则。张无忌学了太极拳,忘记了所有招式,打败了“玄秘二老”,即所谓的“心中无招”。设计模式可以被描述为技巧。如果先学习各种模式,然后忘记所有模式,为所欲为,这可以称为OO的最高境界。哦,可笑,可笑! (JR)
4.3.4 依赖倒置原则
抽象不应该依赖细节,细节应该依赖抽象。
为接口编程,而不是实现。
传递参数,或尝试在复合聚合关系中引用更高级别的类。
主要是在构造对象的时候,可以动态的创建各种具体的对象。当然,如果一些具体的类比较稳定的话,就不需要再做一个抽象类作为它的父类了,感觉就像是在添加更多的内容
4.3.5 接口隔离原则
自定义服务示例,每个接口都应该是一个角色,不多不少,不该做的不做,该做的就做
4.3.6 个抽象类
抽象类不会有实例。一般作为父类作为子类继承,一般包含本系统的通用属性和方法。
注意:在良好的继承关系中,只有叶子节点是具体类,其他节点应该是抽象类,即具体类
不是继承的。将尽可能多的通用代码放入抽象类中。
4.3.7 得墨忒耳法则
最少知识原则。不要和陌生人说话。
4.4、模型的四个基本要素
设计模式使重用成功的设计和架构变得越来越容易。将经过验证的技术表示为设计模式还可以让新系统的开发人员更容易理解他们的设计理念。
4.4.1. 模式名称()
用一两个词描述模式的问题、解决方案和效果的助记符。命名一个新模式会增加我们的设计词汇。设计模式允许我们在更高的抽象层次上进行设计。基于模式词汇,我们和同事可以讨论模式并在编写文档时使用它们。模式名称帮助我们思考并与他人交流设计理念和结果。找到正确的模式名称也是我们设计模式编目工作中最困难的部分之一。
4.4.2. 问题()
描述何时应该使用模式。它解释了设计问题和问题的因果,它可能描述了一个特定的设计问题,例如如何使用对象来表示算法。它还可能描述导致设计不灵活的类或对象结构。有时,问题部分包含使用架构必须满足的先决条件列表。
4.4.3.解()
描述设计的组件、它们之间的关系、它们的职责以及它们如何协同工作。因为模式就像一个模板,可以在许多不同的情况下应用,所以解决方案并不描述具体的具体设计或实现,而是提供设计问题的抽象描述以及如何使用元素的一般组合(类或对象组合)来解决这个问题。
4.4.4. 效果()
描述应用模式的效果以及使用模式的权衡。虽然我们在描述设计决策时并不总是提到模式效应,但它们对于评估设计选择和理解使用模式的成本和收益很重要。软件效果主要与时间和空间的度量有关,它们也表达语言和实现问题。由于重用是面向对象设计的要素之一,模式效应包括其对系统的灵活性、可扩展性或可移植性的影响,通过明确列出这些效应有助于理解和评估这些模式。
4.5、模式概览
就设计模式的类型而言,简单工厂模式是一种创建模式,也称为静态工厂方法( )模式c# 工厂方法模式,但它不是 23 GOF 设计模式之一。简单的工厂模式是工厂对象决定创建产品类的哪个实例。简单工厂模式是工厂模式家族中最简单、最实用的模式。可以理解为不同工厂模式的特殊实现。学习这种模式可以为以后的许多中间模式奠定基础。那么,我们来了解一下什么是简单工厂模式?
让我们分析一个真实案例。每天早上起床洗漱后做什么?吃早餐(这个只针对在外面吃早餐的上班族),坐公交车(我穷只坐公交车,当然很多有钱人都有自己的车,这里不考虑这些)上班在公司,是这样的吗?好,我们来分析一下吃早餐的故事。我们来看看下图:
当我们去买早餐时,早餐店卖什么?你注意到了吗?那里的食物很多,你只要告诉售货员你想要什么样的食物,他就会知道给你什么样的食物。这是什么意思?如果你用面向对象的思维来理解的话,这里的销售员就是一个工厂,他负责根据你的要求退回你需要的食物对象。这正是简单工厂模式的意图。
4.6、模式意图
简单工厂模式根据提供给它的数据返回几个可能类之一的实例。
4.7、 UML 图
以下是简单工厂模式的UML示意图:
4.8、模式参与者
() 角色:接受客户端请求,负责通过请求创建对应的产品对象。
抽象() 角色:它是工厂模式创建的对象的父类或共同拥有的接口。但抽象类或接口。
具体的()对象:工厂模式创建的对象都是这个角色的实例。
4.9、模式实现
通过上面的分析,我们已经清楚地了解了工厂模式中的各种角色和职责。工厂模式是如何通过代码实现的?好,我们继续分析上面吃早餐的故事,做一个简单的例子实现。
1、首先让我们看一下只有一个产品对象的简单工厂模式的实现。其实这很容易理解,好像店里只卖一种食物,这里我们以馒头为例。
1///
2///馒头
3///
阅读
5{
6///
7///构造方法
8///
()
10{}
11
12///
13///售价
14///
=0.5;
17{
18get{;}
19set{price=value;}
20}
21}
OK,对象创建完毕,接下来就是创建()对象了。
1///
2///工厂角色
3///
5{
6///
7///创建一个bun()对象
8///
9///
()
11{
ead();
13}
14}
此时,客户端可以这样调用:
2{
n([]args)
4{
5//通过工厂创建一个产品的实例
=.();
.("一个馒头{0}元!",sb.Price);
8}
9}
以上完成了一个简单工厂模式的简单实现,一个产品一个工厂,工厂负责创建这个产品。但是,实现有一定的缺陷。为每个产品创建一个静态方法来完成产品对象的创建。如果有多个产品,则需要定义多个静态方法来返回不同的对象。就设计原则而言,确实如此。该实现不符合依赖倒置原则(DIP)。如果系统中只有一个产品对象,则此实现非常好。 UML图如下:
2、具有抽象 () 角色的简单工厂模式实现
从上面的分析来看,这个实现要为每个产品创建一个静态方法来完成产品对象的创建。虽然它具有简单工厂的性质c# 工厂方法模式,但似乎并不能完全体现简单工厂模式的意图。简单工厂的目的是根据提供给它的数据返回几个可能类之一的实例。根据意图分析,实现完全满足简单工厂模式意图的程序,需要让工厂根据提供给工厂的数据进行判断,然后返回相应的对象。好的,看看下面的?
8///由于我们只需要获取价格,这里只提供get属性访问器
9///
{get;}
11}
12---------------------------------------------- ------------------------------------
13///
14///馒头
15///
面包:美食
17{
18///
19///构造方法
20///
()
22{}
23
25{
26get
27{
.5;
29}
30}
31}
32---------------------------------------------- ---------- ------------------------------------------
33///
34///包子
35///
:美食
37{
ed()
39{}
40
41///
42///售价
43///
45{
46get
47{
.6;//0.6元一个
49}
50}
51}
52---------------------------------------------- ------------------------------------
53///
54///工厂角色
55///
57{
58///
59///创建一个bun()对象
60///
61///
()
63{
64if(key=="馒头")
65{
ead();
67}
69{
uffed();
71}
72}
73}
74---------------------------------------------- ------------------------------------
76{
in([]args)
78{
79//通过工厂创建产品实例
=.("馒头");
.("一个馒头{0}元!",food.price);
82
=.("包子");
.("一包{0}元!",food.price);
85}
86}
此时的设计完全符合简单工厂模式的意图。顾客( )对早餐店的营业员( )说,我要“包子”,于是营业员根据顾客提供的资料(包子)搜索了很多食物,找到了,交给了客户。
3、模式的演变
某些案例可以由抽象产品来扮演,抽象产品类也是子类的工厂。也就是说,抽象的产品角色扮演着两个角色和职责,在基本定义之外,它还充当工厂角色的职责,负责产品的创建。这里我们在上面例子的基础上做一些适当的修改,新建一个抽象类():
1///
2///兼作抽象产品角色和工厂角色
3///
5{
6///
7///常用字段
8///
;
11{
12get{;}
13set{price=value;}
14}
15
16
()
18{
19if(key=="馒头")
20{
ead();
22}
24{
uffed();
26}
27}
28}
现在,具体产品对象的设计也要修改一下,将原来的IFood接口实现改成继承这个抽象类,如下:
阅读:
2{
()
4{
5this.Price=0.5;//构造函数中初始属性的值
6}
7}
8
:
10{
ed()
12{
.Price=0.6;
14}
15}
通过以上演进,客户端调用如下:
2{
n([]args)
4{
=.("包子");
.("一个包子{0}元!",el.Price);
7}
8}
UML 草图如下:
如果省略抽象产品角色,工厂角色可以与具体产品角色合并。也就是说,一个产品类别就是它自己的工厂。这样,原来三个独立的角色:抽象产品角色、具体产品角色和工厂角色合二为一,这个类负责创建自己的实例。
注意:上面的进化可以直接从上面的程序代码修改,这里就不贴代码了。
4.10、模式优缺点
工厂类包含必要的判断逻辑,可以决定何时创建哪个产品类的实例,客户端可以免除直接创建产品对象的责任,而只是“消费”产品。简单工厂模式就是通过这种方式实现职责分离的。
当产品具有复杂的多层次层次结构时,工厂类只有自己,这是该模式的缺点。因为工厂类集中了所有的产品创建逻辑,一旦不能正常工作,整个系统都会受到影响。
系统难以扩展。一旦添加了新产品,就必须修改工厂逻辑,这可能会导致工厂逻辑过于复杂,违反“开闭”原则(OCP)。此外,简单工厂模式通常使用静态工厂方法,这使得子类无法继承,工厂角色无法形成基于继承的层次结构。
4.11、相关模式
工厂方法模式:每个产品都由专门的工厂创建。它只是一种产品的实现,具有简单工厂的性质。
抽象工厂模式:与工厂方法大致相同。
单例模式:单例的实现与上述模式演变中的最后一种非常相似,只要构造函数是私有的就可以了。