常用设计模式JAVA实现.docx

上传人:b****5 文档编号:29419996 上传时间:2023-07-23 格式:DOCX 页数:19 大小:184.42KB
下载 相关 举报
常用设计模式JAVA实现.docx_第1页
第1页 / 共19页
常用设计模式JAVA实现.docx_第2页
第2页 / 共19页
常用设计模式JAVA实现.docx_第3页
第3页 / 共19页
常用设计模式JAVA实现.docx_第4页
第4页 / 共19页
常用设计模式JAVA实现.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

常用设计模式JAVA实现.docx

《常用设计模式JAVA实现.docx》由会员分享,可在线阅读,更多相关《常用设计模式JAVA实现.docx(19页珍藏版)》请在冰豆网上搜索。

常用设计模式JAVA实现.docx

常用设计模式JAVA实现

DesignMethod

面向对象的几个设计原则:

1、SRP单一职责原则

SRP(单一职责原则,SingleResponsibilityPrinciple):

应该有且仅有一个原因引起类的变化。

通俗说,一个类应该只负责一项职责。

问题描述:

类T负责两个不同的职责:

职责P1,职责P2。

当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。

解决方案:

遵循单一职责原则。

分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。

这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。

这样看似简单易懂的原则,在实际开发中经常违背该原则。

这是因为存在职责扩散,如类T中的职责P因为某种原因,职责P被分化为粒度更细的P1和P2。

由于程序已经写好了,针对这种情况,可以稍微修改下T,让它负责两个职责是个不错的选择,虽然这样违背了SRP原则。

结论,使用单一职责原则有一个问题,“职责”没有一个明确的划分标准,如果把职责划分的太细的话会导致接口和实现类的数量剧增,反而提高了复杂度,降低了代码的可维护性。

所以使用这个职责的时候还要具体情况具体分析。

建议就是接口一定要采用单一职责原则,实现类的设计上尽可能做到单一职责原则,最好是一个原因引起一个类的变化。

2、LSP里氏替代原则

LSP(里氏替代原则,theLiskovSubstitutionPrinciple):

软件中,如果能够使用基类对象,那么一定能够使用其子类对象。

把基类都替换成其子类,程序将不会产生任何错误和异常;反之,则不一定。

因此,在程序中,应该尽量使用基类类型来对对象进行定义,而在运行时在确定其子类类型,用子类对象来替换父类对象。

3、OCP开闭原则

OCP(开闭原则,Open-ClosedPrinciple):

一个软件的实体应当对扩展开放,对修改关闭。

即对于一个已有的软件,如果需要扩展,应当在不需修改已有代码的基础上进行。

4、DIP依赖倒置原则

DIP(依赖倒转原则,DependenceInversionPrinciple):

要针对接口编程,不要针对实现编程。

即对于不同层次的编程,高层次暴露给低层次的应当只是接口,而不是它的具体类。

5、LOD迪米特法则

LoD(迪米特法则,LawofDemeter):

一个软件实体应该尽可能少地与其它实体发生相互作用。

其核心就是类间解耦,低耦合,这样,类的复用才可以提高。

1.简单工厂模式

1.定义

简单工厂模式,即静态工厂模式(StaticFactoryMethod)。

它要求定义一个工厂类,来负责创建其它类的实例,被创建的实例通常具有共同的父类。

2.简单工厂模式演变

(1)首先,写一个Apple、Banana类,并进行实例化,即:

publicclassApple{

publicvoidget(){

System.out.println("采集苹果");

}

}

publicclassBanana{

publicvoidget(){

System.out.println("采集香蕉");

}

}

publicclassMain{

publicstaticvoidmain(String[]args){

Appleapple=newApple();

Bananabanana=newBanana();

apple.get();

banana.get();

}

}

分析上述代码,发现Apple和Banana类都有一个get()采集方法,因此可以将这个公共的方法抽象出来一个借口Fruit,并在该接口中定义该方法,然后让Apple和Banana分别实现该接口。

先看代码:

publicinterfaceFruit{

publicvoidget();

}

publicclassAppleimplementsFruit{

publicvoidget(){

System.out.println("采集苹果");

}

}(Banana略)

publicclassMain{

publicstaticvoidmain(String[]args){

Fruitapple=newApple();

Fruitbanana=newBanana();

apple.get();

banana.get();

}

}

此时,在Main类中,通过使用接口的引用指向子类的对象进行实例化(多态)。

(2)简单模式定义中,要求定义一个工厂类,负责常见其它类的实例。

工厂类定义成:

publicclassFruitFactory{

publicstaticFruitgetApple(){

returnnewApple();

}

publicstaticFruitgetBanana(){

returnnewBanana();

}

}

有了工厂类后,在Main类中进行实例化可以这样:

publicclassMain{

publicstaticvoidmain(String[]args){

Fruitapple=FruitFactory.getApple();

Fruitbanana=FruitFactory.getBanana();

apple.get();

banana.get();

}

}

其实,通过FruitFactory.getApple()与newApple()是等价的,只不过此处是通过FruitFactory返回对象的方式。

上面就是对简单工厂模式进行了实现(FruitFactory类、Fruit接口、Apple/Banana类、主类)。

3.简单工厂模式中的角色

(1)工厂角色Creator:

工厂角色是简单工厂模式的核心(FruitFactory.java)。

它负责创建所有实例的内部逻辑。

工厂类可以被外界直接调用(Main类中FruitFactory.getApple()),并创建所需产品对象。

根据需要创建不同的产品,以抽象产品类型返回具体产品(FruitFactory类中的两个方法)。

(2)抽象产品Product:

是指简单工厂模式所创建的所有对象(apple/banana)的父类(Fruit接口),它负责描述所有实例所共有的公共的接口(apple/banana都有的get方法)。

(3)具体产品ConcreteProduct:

简单工厂模式所创建的具体实例对象。

4.改进

工厂类中getApple()、getBanana()方法,可以改成一个getFruit(),在该方法中进行判断是apple还是banana,即:

publicclassFruitFactory{

publicstaticFruitgetFruit(Stringtype)throwsInstantiationException,

IllegalAccessException{

if(type.equalsIgnoreCase("apple")){

returnApple.class.newInstance();

}elseif(type.equalsIgnoreCase("banana")){

returnBanana.class.newInstance();

}else{

returnnull;

}

}

}

publicclassMain{

publicstaticvoidmain(String[]args)throwsInstantiationException,

IllegalAccessException{

Fruitapple=FruitFactory.getFruit("aPPle");

Fruitbanana=FruitFactory.getFruit("banana");

apple.get();

banana.get();

}

}

5.继续改进

由于上面Apple.class.newInstance()等价于newApple();可改成Class.forName(type)动态加载类的方式:

publicclassFruitFactory{

publicstaticFruitgetFruit(Stringtype)throwsClassNotFoundException,

InstantiationException,IllegalAccessException{

Classfruit=Class.forName(type);

return(Fruit)fruit.newInstance();

}

}

publicclassMain{

publicstaticvoidmain(String[]args)throwsClassNotFoundException,InstantiationException,IllegalAccessException{

Fruitapple=FruitFactory.getFruit("Apple");

Fruitbanana=FruitFactory.getFruit("Banana");

apple.get();

banana.get();

}

}

改成这样的缺点是,Main类中传递的参数必须跟类名相同(必须为Apple、Banana),不够灵活。

总结:

第一种方法最差;改进后的好些,但if判断太多;继续改进后的方法好些。

6.简单工厂模式优缺点

优点:

工厂类是整个模式的关键。

包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。

通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。

而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。

缺点:

1>由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类(产品),则就需要改变工厂类了。

  2>当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。

这些缺点在工厂方法模式中得到了一定的克服。

2.工厂方法模式FactoryMethod

1.定义

工厂方法模式又称为多态工厂模式(因为具体工厂类都有一个公共接口,也可以是抽象类),它要求定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。

这样做的好处是当引进新的工厂时,只需要添加具体产品工厂,而不需要修改其它具体工厂和抽象工厂,满足OCP原则。

2.工厂方法模式演变

Apple.javaBanana.javaFruit.java不变

FruitFactory.java

publicinterfaceFruitFactory{

publicFruitgetFruit();

}

AppleFactory.java

publicclassAppleFactoryimplementsFruitFactory{

publicFruitgetFruit(){

returnnewApple();

}

}

BananaFactory.java(略)

publicclassMain{

publicstaticvoidmain(String[]args){

FruitFactoryf1=newAppleFactory();

Fruitapple=f1.getFruit();

apple.get();

FruitFactoryf2=newBananaFactory();

Fruitbanana=f2.getFruit();

banana.get();

}

}

此时,再增加Pear类时,只需要添加PearFactory类即可,不需要修改FruitFactory类,所以满足OCP原则。

3.工厂方法中的角色

(1)抽象工厂角色Creator:

工厂方法模式的核心。

在该模式下创建的所有工厂类都必须实现该接口。

(2)具体工厂角色ConcreteCreator:

具体工厂类是抽象工厂的实现,负责实例化产品对象。

并受到应用程序调用以创建产品对象。

(3)抽象产品角色Prodect(与简单工厂模式相同):

是指简单工厂模式所创建的所有对象(apple/banana)的父类(Fruit接口),它负责描述所有实例所共有的公共的接口(apple/banana都有的get方法)。

(4)具体产品角色ConcreteCreator(与简单工厂模式相同):

工厂方法模式所创建的具体实例对象。

4.简单工厂模式VS工厂方法模式

(1)核心不同。

简单工厂模式的核心是一个具体工厂类;工厂方法模式核心是一个抽象工厂类(接口)。

(2)简单工厂模式不满足OCP原则,而工厂方法模式满足OCP原则。

5.应用

3.抽象工厂模式AbstractFactory

1.概念

(1)产品等级结构:

一个等级结构是由相同结构的产品组成的。

(2)产品族:

位于不同的等级结构中、功能相关联的产品组成的家族。

一个产品族对应一个具体工厂。

如图所示。

2.定义

抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象。

3.抽象工厂类例子

Step1:

(1)Fruit接口不变

publicinterfaceFruit{

publicvoidget();

}

(2)定义抽象类实现Fruit接口,并将方法定义成抽象。

如Apple类。

publicabstractclassAppleimplementsFruit{

publicabstractvoidget();

}

(3)实现类NorthApple,即:

publicclassNorthAppleextendsApple{

@Override

publicvoidget(){

System.out.println("北方苹果");

}

}

Step2

(1)抽象工厂FruitFactory接口中定义如下

publicinterfaceFruitFactory{

publicFruitgetApple();//实例化apple

publicFruitgetBanana();

}

(2)NorhFruitFactory类实现FruitFactory接口,即

publicclassNorthFruitFactoryimplementsFruitFactory{

publicFruitgetApple(){

returnnewNorthApple();

}

publicFruitgetBanana(){

returnnewNorthBanana();

}

}

Step3:

Main类中调用

publicclassMain{

publicstaticvoidmain(String[]args){

FruitFactoryff=newNorthFruitFactory();

FruitnorthApple=ff.getApple();

northApple.get();

}

}

分析:

若增加“北方香蕉”,则只需添加Banana抽象类和NorthBanana具体类即可。

而想增加“南方香蕉”,则只需添加SouthBanana具体类和SouthFruitFactory实现类即可。

(4)增加“温室苹果”和“温室香蕉”。

首先,添加各自的具体产品类WenShiApple、WenShiBanana。

其次,都是“温室”,所以属于一个产品族,所以要创建一个具体工厂类WenShiFruitFactory。

所以从增加产品族方面来讲,抽象工厂模式满足OCP原则。

但若增加一个产品等级Pear,则需要修改抽象工厂类以及每一个具体工厂类,所以从产品等级方面讲,抽象工厂模式不满足OCP原则。

4.抽象工厂模式角色

(1)抽象工厂(Creator)角色:

抽象工厂模式的核心,包含对多个产品结构的声明,任何工厂类都必须实现这个接口。

(2)具体工厂(ConcreteCreator)角色:

具体工厂类是抽象工厂的一个实现,负责实例化某个产品族中的产品对象。

(3)抽象产品(Product)角色:

抽象工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

(4)具体产品(ConcreteProduct)角色:

抽象工厂模式所创建的具体实例对象。

总结:

南方苹果、南方香蕉、南方梨属于一个产品簇,对于南方水果工厂,而南方属于一个产品等级。

北方苹果、北方香蕉、北方梨属于一个产品簇,对应北方水果工厂,而北方属于一个产品等级。

同理,温室香蕉、温室苹果、温室梨属于一个产品簇,对应温室水果工厂,而温室属于一个产品等级。

因此,增加产品簇时,满足OCP;而增加产品等级时不满足OCP。

抽象工厂中方法对应产品结构,具体工厂对应产品族。

4.单例模式

1.定义

单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。

也就是说,在整个程序空间中,该类只存在一个实例对象。

核心:

保证一个类只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

2.单例模式满足以下三个要点:

(1)某个类只能有一个实例,该类称为单例类;

(2)它必须自行创建这个实例类;

(3)必须自行向整个系统提供这个实例。

3.单例模式需满足:

(1)私有的构造方法,以保证外部无法创建类实例。

(2)私有的静态的类型引用,因为静态就可以保证只有一个变量引用。

(3)提供获取实例的全局静态方法,方法名一般为getInstance()。

4.单例模式应用场景

(1)每台计算机有若干打印机,但只能有一个打印控制器,以避免两个打印作业同时输出到打印机中。

(2)数据库连接池,只能有一个,它自行创建并运行其他模块访问它。

(3)

5.单例模式有三种实现方式

因为实例化,是调用默认的构造器进行实例化,所以构造方法私有化后,外部类将将不能进行实例化。

要外部类能进行实例化,需提供一个全局的静态方法,通过类名调用该静态方法,进行实例化,如:

publicclassPerson{

//构造器私有化

privatePerson(){

}

//构造器私有化后,如何进行实例化呢?

提供一个全局的静态方法,这样,就可以通过类名调用该方法进行实例化了。

publicstaticPersongetPerson(){

returnnewPerson();

}

}

这样,外部类仍然可以创建该类的多个实例,不能满足单例模式。

因此有了如下实现方式。

(1)恶汉式:

把new语句写在类型引用变量定义的地方,然后getInstance()直接返回就可以了,即:

publicclassPerson{

privatestaticPersonperson=newPerson();//静态类型,创建实例

privatePerson(){};//私有的构造方法,防止外部类创建。

publicstaticPersongetPerson(){//获取实例方法

returnperson;

}

}

恶汉式:

实现简单。

但是,在不需要的时候,白创建了对象,造成资源的浪费。

(2)懒汉式:

在全局静态方法中,判断实例是否为空,若为空,则实例化;如不为空,则返回该实例对象。

即:

publicclassPerson{

privatestaticPersonperson;//静态类型引用

publicstaticPersongetPerson(){

if(person==null){

returnperson=newPerson();//创建实例

}

returnperson;

}

privatePerson(){};

}

上述方法有一个缺点,即线程是不安全的。

比如,线程A进入到if语句里,但在创建实例前暂停了。

此时,线程B也过来了并执行了实例化。

这是,线程A恢复了,它又执行实例化的创建,这样,就创建了两个实例,因此是不安全的。

为了保证线程安全,需要加上synchronized关键字保证线程同步。

即:

publicstaticsynchronizedPersongetPerson(){

if(person==null){

returnperson=newPerson();

}

returnperson;

}

这样,当线程A进入该方法后,会独占该方法。

其它线程再来时,需要等待第一个线程使用完该方法后,才能执行该方法,保证了线程安全。

上述方法是同步方法,也可以只同步实例的创建上,即:

懒汉式:

需要对象时,才创建,不会造成资源浪费(但若开始时,对象以实例化,则可能造成资源浪费)。

(3)双重检查(也属于懒汉式)

懒汉式中,若现在person已经实例化了,此时,来了线程A,执行上述同步方法。

这时,线程C、线程D等也来了,就需要等待A执行完。

而person早已实例化,因此即使在轮到C、D等线程执行方法时,也不会执行if中的内容,所以C、D的等待,造成了资源的浪费。

因此,为了防止资源浪费,只需要同步if中的对象的实例化上。

即:

publicstaticPersongetPerson(){

if(person==null){

synchronized(Person.class){

returnperson=newPerson();

}

}

returnperson;

}

上述只进行了一次检查。

还有一种情况:

person还没初始化。

此时线程A、B来了,执行if语句,A先执行person的初始化,结束后,B也会执行初始化。

这样,又会造成多次实例化。

解决办法是,在同步中执行实例化前,再加一个判断,即:

publicstaticPersongetPerson(){

if(person==null){

synchronized(Person.class){

if(person==null){

returnperson=newPerson();

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 职业教育 > 职高对口

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1