一、设计模式的概念
设计模式是对被用来在特定场景下解决一般设计问题的类和相互通信的对象的描述。设计模式是针对问题和解的抽象,是对一系列具有共同的问题的完整的解决方案。设计模式强调系统的复用性,它帮助人们做出有利于系统复用的选择,从而避免设计损害系统的复用性,是可复用面向对象软件的基础。一个完整的设计模式主要由模式名称、问题、解决方案和效果四个基本要素组成。
设计模式中最重要的思想就是“封装变化的概念”。这是绝大多数射进模式的核心概念。一方面,设计出来的软件应该体现出一定的灵活性,以适应可能的变化;另一方面,必须把这种灵活性所带来的软件内部的复杂性封装起来,为外界提供一个简单而稳定的访问接口,这两方面分别从内部实现和外部接口上提高了软件的复用性。这就要求我们在进行可复用面向对象软件设计时应遵循:不断剥离出系统中可变化的部分并把这部分封装起来。
二、设计模式将带来什么
1、设计模式带来了一套通用的设计词汇
各种设计模式的名字组成了一个词汇表,这个词汇表可以帮助开发人员更好地交流。设计模式为设计者们交流讨论、书写文档以及探索各种不同设计提供了一套通用的设计词汇。设计模式使设计者可以在比设计表示或编程语言更高的抽象级别上谈论一个系统,从而降低了其复杂度。
2、书写文档和学习的辅助手段
当一个系统的文档描述系统所用的模式时,它们可以帮助人们更快地理解这个系统。学习这些设计模式有助于设计者理解已有的面向对象系统,同时也能提高设计者的设计水平。而且,按照一个系统所使用的设计模式来描述该系统可以使他人理解起来容易得多,否则,就必须对该系统的设计进行逆向工程来弄清其使用的设计模式。有一套通用的设计词汇的好处是你不必描述整个设计模式,而只要使用它的名字,当他人读到这个名字就会理解系统的设计。
3、设计模式是现有方法的一种补充
设计模式总结了专家的经验,使得普通的开发人员可以使用。面向对象方法可用来促进良好的设计,教新手如何设计,以及对设计活动进行标准化。设计模式是面向对象设计方法所缺少的一块重要内容。这些设计模式展示了如何使用诸如对象、继承和多态等基本技术。它们也展示了如何以算法、行为、状态或者需生成的对象类型将一个系统参数化。设计模式在将一个分析模型转换为一个实现模型时特别有用。一个成熟的设计方法不仅要有设计模式,还可有其他类型的模式,如分析模式,用户界面设计模式或者性能调节模式等等,但设计模式是最主要的部分。
4、设计模式为系统重构提供了目标
无论系统是否用脑海中的模式来设计,它们都可以使更改系统机构变得容易。开发可复用软件的一个问题是开发者常常不得不重新组织或重构软件系统。设计模式可以帮助开发者重新组织一个设计,同时还能减少以后的重构工作。设计模式记录了许多重构产生的设计结构。在设计初期使用这些模式可以防止以后的重构。而且即使是在系统建成以后才了解使用这些模式,它们仍可以教设计者如何修改系统。
三、三种设计模式的介绍
在用设计模式进行面向对象设计时,特别强调两个面向对象设计的原则:针对接口编程而不是针对实现编程和优先使用组合而不是类继承。其中针对接口编程而不是针对实现编程要求不将变量声明为某个特定的具体类,而是让它遵从抽象类所定义的接口。然而,有时不得不在系统的某个地方实例化具体的类,这时创建型模式(Factory Method,Abstract Factory,Builder,Prototype,Singleton)可以做到这点。在这里主要通过具体的实例介绍三种创建型设计模式:工厂方法模式(Factory Method),抽象工厂模式(Abstract Factory),以及生成器模式(Builder)。
假设有这样的一个企业:该企业有四川和重庆两个分公司,每个子公司都有一套自己的薪资计算规则,每个月每个公司都要计算自己公司的薪资。那么应该如何为该企业设计一套薪资系统呢?
我们可能这样想,首先抽象出一个薪资类,然后所有的子公司的薪资类都继承这个抽象的薪资类,最后在客户端判断是哪个子公司,然后新建该子公司的薪资类对象。如果是这样,那么当这个企业的子公司有许多的时候,客户端的条件判断岂不是要写许多,代码就会变得很长。
我们可以再创建一个类,把具体的判断语句抽取到这个类中,在客户端只负责薪资类的计算,这样可以解决在客户端要写许多判断语句的问题。还有一个问题就是如果该企业的子公司有很多,那么判断语句中的if…else语句就会很多,代码就不好看,而且一般在薪资计算前,都会有一些初始化工作要做,把许多公司的初始化工作都放在一个类中来做,代码量就可想而知了。所以,在这里,我们需要使用工厂方法模式来进行设计。
1、工厂方法模式(Factory Method)
(1)意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
(2)适用性:
1)当一个类不知道它所必须创建的对象的类的时候;
2)当一个类希望由它的子类来指定它所创建的对象的时候;
3)当类将创建对象的职责委托给多个帮助子类中的某一个,并且希望将哪一个帮助子类是代理者这一信息局部化的时候。
(3)参与者:
1)Product——定义工厂方法所创建的对象的接口
2)ConcreteProduct——实现Product接口
3)Creator——声明工厂方法,该方法返回一个Product类型的对象
4)ConcreteCreator——重定义工厂方法以创建一个Product对象。
(4)实例代码:
这里我们还是以上面的那个企业的薪资系统为例。代码如下:
//***
抽象的薪资类定义
***
//********Salary.java**********
interface
Salary{
void
computerSalary();
}
//***
四川子公司的薪资类的代码
*****
//****SCSalary.java******
class
SCSalary
implements
Salary{
public
void
computerSalary(){
System.
out
.println(
"
开始计算四川子公司的薪资
"
);
}
}
//***
重庆子公司的薪资类的代码
*****
//****CQSalary.java*****
class
CQSalary
implements
Salary{
public
void
computerSalary(){
System.
out
.println(
"
开始计算重庆子公司的薪资
"
);
}
}
//***
创建一个只负责定义创建方式的抽象的工厂类
***
//***Factory.java*******
interface
Factory{
public
Salary createSalary();
}
//***
四川子公司的工厂类
***
//***SCSalaryFactory.java***
class
SCSalaryFactory
implements
Factory{
public
Salary createSalary(){
return
new
SCSalary();
}
}
//***
重庆子公司的工厂类
***
//***CQSalaryFactory.java***
class
CQSalaryFactory
implements
Factory{
public
Salary createSalary(){
return
new
CQSalary();
}
}
//***
客户端代码
***
//***Client.java***
public
class
Client{
public
static
void
main(String [] args){
Factory factory=
new
SCSalaryFactory();
Salary salary=factory.createSalary();
salary.computerSalary();
factory=
new
CQSalaryFactory();
salary=factory.createSalary();
salary.computerSalary();
}
}
在实例中,创建了一个只负责定义薪资创建方式的抽象工厂类
Factory
,而在客户端就只负责对象的调用即可。从而避免了把对象的创建和组装都放在客户端,造成客户端代码很复杂,同时也明确了各个类的职责。
(5
)小结:
在工厂方法模式中,客户端不需要负责对象的创建,而是把这个责任交给了具体的工厂类,客户端只负责对象的调用,从而明确了各个类的职责。如果有新的产品加进来,只需要新增加一个具体的产品工厂类(
ConcreteCreator
)和具体的产品类
(ConcreteProduct)
就可以了,不会影响到原来已有的其他代码,代码量不会变大,后期维护更加容易,增强了系统的可扩展性。
在工厂方法模式中,一个具体的工厂类负责创建一个单独的产品,如果有两个不同的产品要创建,就需要两个不同的工厂类,即使这两个产品之间存在相关性,同样还需要两个不同的工厂类。同样如此,对于上面的实例,该企业计算完薪资,如果还要计算税收,倘若采用工厂方法模式,那么就需要定义两个抽象工厂类,分别用来定义薪资和税收,然后每个子公司分别继承这两个抽象工厂类以实现具体的工厂类,这样一来,每个子公司至少要
2
个工厂类:薪资、税收。如果该企业的子公司有许多,工厂类的数量就可想而知了。这时我们可以重新定义一个抽象的工厂类,用来定义创建薪资类和税收类的方式,这就是抽象工厂模式。
2
、抽象工厂模式
(Abstract Factory)
(
1
)意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
(
2
)适用性:
1
)一个系统要独立于它的产品的创建、组合和表示时;
2
)一个系统要由多个产品系列中的一个来配置时;
3
)当你要强调一系列相关的产品对象的设计以便进行联合使用时;
4
)当你提供一个产品类库,而只想显示它们的接口而不是实现时。
(3)参与者:
1)AbstractFactory——声明一个创建抽象产品对象的操作接口
2)ConcreteFactory——实现创建具体产品对象的操作
3)AbstractProduct——为一类产品对象声明一个接口
4)ConcreteProduct——实现AbstractProduct,定义一个将被相应的具体工厂创建的产品对象
5)Client——仅使用由AbstractFactory和AbstractProduct类声明的接口。
(4)实例代码:
税收类和薪资类的设计一样,先设计一个抽象的接口,然后每个子公司的税收类都继承该接口。代码如下:
//***
抽象的薪资类定义
***
//********Salary.java**********
interface
Salary{
void
computerSalary();
}
//***
四川子公司的薪资类的代码
*****
//****SCSalary.java******
class
SCSalary
implements
Salary{
public
void
computerSalary(){
System.
out
.println(
"
开始计算四川子公司的薪资
"
);
}
}
//***
重庆子公司的薪资类的代码
*****
//****CQSalary.java*****
class
CQSalary
implements
Salary{
public
void
computerSalary(){
System.
out
.println(
"
开始计算重庆子公司的薪资
"
);
}
}
//***
抽象的税收类定义
//***Tax.java***
interface
Tax{
void
computerTax();
}
//***
四川子公司的税收类代码
***
//***SCTax.java***
class
SCTax
implements
Tax{
public
void
computerTax(){
System.
out
.println(
"
开始计算四川公司的税收
"
);
}
}
//***
重庆子公司的税收类代码
***
//***CQTax.java***
class
CQTax
implements
Tax{
public
void
computerTax(){
System.
out
.println(
"
开始计算重庆公司的税收
"
);
}
}
//***
定义一个抽象的工厂类,用来定义创建薪资类和税收类的方式
***
//***Factory.java*******
interface
Factory{
Salary createSalary();
Tax createTax();
}
//***
四川子公司的抽象工厂类
***
//***SCFactory.java***
class
SCFactory
implements
Factory{
/*
创建四川子公司的薪资对象
*/
public
Salary createSalary(){
return
new
SCSalary();
}
/*
创建四川子公司的薪资对象
*/
public
Tax createTax(){
return
new
SCTax();
}
}
//***
重庆子公司的抽象工厂类
***
//***CQFactory.java***
class
CQFactory
implements
Factory{
/*
创建重庆子公司的薪资对象
*/
public
Salary createSalary(){
return
new
CQSalary();
}
/*
创建重庆子公司的薪资对象
*/
public
Tax createTax(){
return
new
CQTax();
}
}
//***
客户端代码
***
//***Client.java***
public
class
Client{
public
static
void
main(String [] args){
Factory factory=
new
SCFactory();
Salary salary=factory.createSalary();
salary.computerSalary();
Tax tax=factory.createTax();
tax.computerTax();
factory=
new
CQFactory();
salary=factory.createSalary();
salary.computerSalary();
tax=factory.createTax();
tax.computerTax();
}
}
在这个实例中,创建了一个抽象工厂类
Factory
来定义薪资类和税收类的创建,而不是分别定义两个抽象的工厂类,分别负责定义薪资类和税收类的创建,从而避免了程序中出现许多工厂类,增加程序代码复杂度。
(5
)小结:
与工厂方法模式相同,在抽象工厂模式中,客户端不再负责对象的创建,而是把这个责任交给了具体的工厂类,客户端只负责对对象的调用,从而明确了各个类的职责。当一系列相互关联的产品被设计到一个工厂类里后,客户端的调用将会变得非常简单,而且,如果要更换这一系列的产品,只需要更换一个工厂类即可。但是如果有新的产品加进来,则需要修改抽象工厂类的设计,并同时修改实现这个抽象工厂类的具体工厂类,需要额外编写代码,增加了工作量。
在抽象工厂模式中,把相互关联的产品的对象的组装都放在了客户端,如果产品很多,客户端就会变得非常臃肿;但如果放在工厂类中,则又违反了单一职责的原则,使得工厂类既要负责对象的创建,又要负责对象的组装。当然,我们可以创建一个组装类来负责对象的组装,工厂类只负责对象的创建,而客户端直接调用组装类就可以了,这就是生成器模式。
3
、生成器模式
(Bulider)
(
1
)意图:将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。
(
2
)适用性:
1
)当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装方式时
2
)当构造过程必须允许被构造的对象有不同的表示时。
(3)参与者:
1)Builder——为创建一个Product对象的各个部件指定抽象接口
2)ConcreteBuilder——实现Builder的接口以构造和装配该产品的各个部件
3)Director——构造一个使用Builder接口的对象
4)Product——表示被构造的复杂对象,包含定义组成部件的类。
(4)实例代码:
//***
抽象的薪资类定义
***
//********Salary.java**********
interface
Salary{
void
computerSalary();
}
//***
四川子公司的薪资类的代码
*****
//****SCSalary.java******
class
SCSalary
implements
Salary{
public
void
computerSalary(){
System.
out
.println(
"
开始计算四川子公司的薪资
"
);
}
}
//***
重庆子公司的薪资类的代码
*****
//****CQSalary.java*****
class
CQSalary
implements
Salary{
public
void
computerSalary(){
System.
out
.println(
"
开始计算重庆子公司的薪资
"
);
}
}
//***
抽象的税收类定义
//***Tax.java***
interface
Tax{
void
computerTax();
}
//***
四川子公司的税收类代码
***
//***SCTax.java***
class
SCTax
implements
Tax{
public
void
computerTax(){
System.
out
.println(
"
开始计算四川公司的税收
"
);
}
}
//***
重庆子公司的税收类代码
***
//***CQTax.java***
class
CQTax
implements
Tax{
public
void
computerTax(){
System.
out
.println(
"
开始计算重庆公司的税收
"
);
}
}
//***
定义一个抽象的工厂类,用来定义创建薪资类和税收类的方式
***
//***Factory.java*******
interface
Factory{
Salary createSalary();
Tax createTax();
}
//***
四川子公司的抽象工厂类
***
//***SCFactory.java***
class
SCFactory
implements
Factory{
/*
创建四川子公司的薪资对象
*/
public
Salary createSalary(){
return
new
SCSalary();
}
/*
创建四川子公司的薪资对象
*/
public
Tax createTax(){
return
new
SCTax();
}
}
//***
重庆子公司的抽象工厂类
***
//***CQFactory.java***
class
CQFactory
implements
Factory{
/*
创建重庆子公司的薪资对象
*/
public
Salary createSalary(){
return
new
CQSalary();
}
/*
创建重庆子公司的薪资对象
*/
public
Tax createTax(){
return
new
CQTax();
}
}
//***
组装类,负责产品的组装
***
//***Director.java***
class
Director{
private
Factory
factory
;
public
Director(Factory factory){
this
.
factory
=factory;
}
public
void
computer(){
Salary salary=
factory
.createSalary();
salary.computerSalary();
Tax tax=
factory
.createTax();
tax.computerTax();
}
}
//***
客户端代码
***
//***Client.java***
public
class
Client{
public
static
void
main(String [] args){
Director director=
new
Director(
new
SCFactory());
director.computer();
}
}
在这里,我们创建了一个工厂类
Factory
负责定义薪资类和税收类的创建,并且创建了一个创建者类
Director
负责对象的组装,而在客户端则只需要调用这个创建者类即可,从而明确了各个类的职责,使得各个类更好的分工。
(5
)小结:
在构造器模式中,客户端不再负责对象的创建和组装,而是把这个创建的责任交给了具体的创建者类,把组装的责任交给组装类,客户端只负责对象的调用,从而明确了各个类的职责。
虽然利用构造器模式可以创建出不同类型的产品,但如果产品之间的差异非常大,就需要编写多个创建这类才能实现,这是如果结合工厂模式更好。
相关推荐
设计模式是面向对象设计的重要组成部分,它们提供了一种经过验证的解决方案来应对软件开发中的常见问题。通过学习和应用这些模式,Java程序员可以编写出更加灵活、易于维护和扩展的代码。本文介绍了23种设计模式的...
#### 二、设计模式简介 设计模式是一种通用的、在特定情境下用来解决设计问题的方法。它们为常见问题提供了一个标准化的解决方案,可以提高代码的可重用性、灵活性和可维护性。本书中所提到的23种设计模式是由Erich...
设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决问题的可重用解决方案。这份名为“设计模式图形非常精美”的资源提供了一个详细且直观的设计模式查询手册,通过清晰的图表和视觉表现,使得理解和应用...
C++ Qt设计模式(第2版)是美国萨福克大学已使用十余年的经典教程,利用跨平台开源软件开发框架Qt阐释了C++和设计模式中的主要思想。全书共分四个部分:第一部分介绍C++、UML、Qt、模型-视图、SQL、XML、设计模式等...
### 设计模式简介 设计模式是在软件开发过程中解决常见问题的一种通用可重用的解决方案。它们代表了在特定情况下经过验证的最佳实践,并为常见的设计挑战提供了标准答案。设计模式不仅有助于提高代码的质量和可维护...
设计模式分为三大类:创建型、结构型和行为型。创建型模式涉及到对象的实例化过程,如单例模式、工厂方法模式、抽象工厂模式等;结构型模式关注如何组合对象和类以形成更大的结构,如适配器模式、装饰器模式、代理...
### 设计模式简介 #### 一、设计模式概述 设计模式是一种被广泛接受的软件设计方法,它提供了针对常见问题的可复用解决方案。通过学习和应用设计模式,开发者能够更好地构建模块化、可复用且易于理解的软件系统。 ...
#### 三、Ajax设计模式概述 设计模式是在软件开发过程中为解决特定问题而形成的最佳实践。对于Ajax应用而言,一些常见的设计模式可以帮助开发者构建高效、可维护的Web应用程序。 ##### 3.1 常见的Ajax设计模式 - *...
#### 一、单例设计模式简介 单例设计模式是一种常用的软件设计模式,其目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如数据库连接池、日志处理、线程池等,在这些场景中...
### 设计模式简介 设计模式是在软件工程领域中,解决特定问题的一系列可复用的解决方案。它们代表了在某一类问题上,经过验证的最佳实践,能够帮助开发者避免常见的陷阱,并提供了一种通用的语言来描述代码结构,...
### 一、设计模式简介 #### 1.1 定义 设计模式是在特定情境下解决软件设计中反复出现的问题的一种模板或指导方针。它们提供了一种经过验证的解决方案,有助于提高代码的复用性和可读性。 #### 1.2 分类 设计模式...
工厂模式作为一种重要的设计模式,在实际开发中有着广泛的应用。通过对工厂模式的学习和理解,开发者可以更好地设计出灵活、可扩展的系统架构。在使用工厂模式时,需要注意其适用场景和限制条件,合理选择不同的工厂...
随着Node.js在企业级应用中的普及度不断提高,掌握其设计模式变得尤为重要。通过学习这些模式,开发者可以更高效地解决常见的编程问题,并提高代码的质量和维护性。 #### 三、作者简介 - **Mario Casciaro**:一位...
数据库设计范式是关系数据库设计的核心概念,它们是用来确保数据的一致性、减少冗余、避免数据异常的关键原则。在数据库领域,特别是Oracle等大型关系型...在进行数据库设计时,理解并合理运用这些范式是至关重要的。
#### GoF23种设计模式简介 《设计模式:可复用面向对象软件的基础》一书中,四位作者(被称为Gang of Four,即GoF)总结了23种经典的面向对象设计模式。这些模式被广泛地应用于软件开发中,成为了设计模式领域的...
#### 二、设计模式简介 设计模式是一系列被广泛接受的解决常见问题的方案,这些解决方案通常在特定情境下被证明是有效的。它们提供了在设计过程中遇到某些常见问题时的一种标准参考框架,帮助开发者更好地组织代码...
### 一、设计模式简介 设计模式是一种在特定情况下解决软件设计问题的经验总结,它提供了一种通用的解决方案模板,可以帮助开发者更好地组织代码结构、降低模块间的耦合度并提高系统的灵活性。对于Android开发者而...
### J2EE设计模式简介 J2EE(Java 2 Platform, Enterprise Edition)是Sun Microsystems公司发布的一个用于开发企业级应用的标准平台。它基于Java SE并添加了更多面向服务化、分布式计算环境的功能,如EJB...