JAVA设计模式(一)
----工厂模式
引言
首先举一个现实生活中的例子:
我今天正要出门,想让老婆帮我拿一件衣服,这时我就要先告诉老婆我今去干什么……
如果告诉老我去上班,那么老婆就会拿出西服;
如果告诉老婆我去参加酒会,老婆就会拿出晚礼服,
如果告诉老婆我要出去玩,老婆就会拿出休闲装;
好了,我们来分析一下上面的例子,
(1)老婆 ——— 在上面例子中充当工厂的角色,负责具体挑选(实例化)哪件衣服。
(2)我索要一件衣服这个事情 ——— 代表向工厂发出的请求,通常以方法的形式定义在工厂类中,负责调度实例化产品(衣服);
(3)去干什么——— 干的具体内容就是向工厂发出请求的参数,工厂会根据参数实例化产品。
(4)我要的是产品 ———“衣服”,西服,晚礼服,休闲装都是他的子类,衣服就是工厂中产品的抽象类,在其中定义一个业务接口,也就是这个产品要完成的行为,具体实现留给他的实现类处理。
(5)下面只剩下西服,晚礼服,休闲装了,他们就是产品的具体实现类。实现接口中的行为,通常这个行为就是指不同产品的业务代码。
分类
简单工厂模式
简单工厂模式,又名静态工厂模式,从名字可以判断他的构成很简单,且目的单一,就是定义一个用于创建对象的接口。
下面我们先来看一下它组成:
工厂类角色
它是这个模式的核心,可能包含一些必要的业务逻辑和判断逻辑,在JAVA中通常由一个具体的类实现。
代码:
我们把老婆看成一个工厂类角色,负责衣服的挑选和调配。
public class WifeFactory { public static final String EVENING = "evening"; // 晚会 public static final String PARTY = "party";// 休闲 public static final String WORKING = "work";// 上班
public static Clothing getRightClothing(String activity) { if (activity.equals(WORKING)) { return new Suit(); } else if (activity.equals(PARTY)) { return new SportWear(); } else if (activity.equals(EVENING)) { return new EveningWear(); } return null; } } |
抽象产品类角色
在此例中衣服为我们的抽象类产品
public interface Clothing { // 定义穿这件衣服要完成的业务逻辑 public void putOnCloth(); } |
具体产品类角色
public class EveningWear implements Clothing { @Override public void putOnCloth() { // TODO Auto-generated method stub System.out.print("我穿晚礼服去参加酒会!"); } } |
public class SportWear implements Clothing { @Override public void putOnCloth() { // TODO Auto-generated method stub System.out.print("我穿休闲装去放松了!"); } } |
public class Suit implements Clothing { @Override public void putOnCloth() { // TODO Auto-generated method stub System.out.print("我穿西服去工作了!"); } } |
终于到我出场了,我要去参加休闲聚会了!!
public static void main(String[] args) { // TODO Auto-generated method stub Clothing c=WifeFactory.getRightClothing(WifeFactory.PARTY); c.putOnCloth(); } |
工厂方法模式
简单工厂模式中,工厂类负责所有产品的调配,但我们想增加一个产品时,就必须在工厂中增加相对于该产品的判断逻辑,这显然不符合开闭原则,而且随着产品结构的复杂性增加,必将使我们的工厂不堪重负,于是产生了解决该问题的模式——工厂方法模式。
工厂模式方法中去掉了简单工厂中工厂方法的静态属性,使得方法可以被子类继承,来分担工厂的压力,每一个(一类)产品都有自己对应的工厂,打个比方我觉得老婆替我调配衣服太累了,于是我找了几个保姆,专门负责替我拿不同的衣服,老婆是总管,这要管好他们就行了。
这样一来,你也应该能够猜出,工厂模式方法的组成了:
抽象工厂角色
它是工厂方法模式的核心,具体 工厂必须实现的接口和继承的父类。在java中通常由抽象类或者接口实现。
如果定义为抽象类,我们还可把一些子类工厂创建对象后前后的逻辑增加进来。比如下例中衣服的熨烫,整理….
public interface WifeFactory { public Clothing getRightClothing(String activity); } |
具体工厂角色
public class EveningFactory implements WifeFactory { @Override public Clothing getRightClothing() { // TODO Auto-generated method stub return new EveningWear(); } } |
public class SportWearFactory implements WifeFactory { @Override public Clothing getRightClothing() { // TODO Auto-generated method stub return new SportWear(); } } |
public class SuitFactory implements WifeFactory { @Override public Clothing getRightClothing() { // TODO Auto-generated method stub return new Suit(); } } |
抽象产品角色和具体产品角色
抽象产品角色和具体产品角色与简单工厂方法的实现类似,这里不再累赘。
下面看看调用过程:
public static void main(String[] args) { WifeFactory factory=new SportWearFactory(); Clothing c=factory.getRightClothing(); c.putOnCloth(); } |
小结
上面这样的结构带来的好处就是,增加了代码的灵活性,但我们想增加一件衣服时,我们不用像简单工厂那样去修改工厂类,也就是说不用修改我们以前的任何代码,而只需要增加相应的具体产品类和具体工厂类就可以了,这样也是符合开闭原则的。
我们不难发现一个问题当产品种类大量增加时,就会导致出现大量的工厂方法,这是我们不愿意看到的,所以在实际使用中我们可以使用简单工厂和工厂方法模式相结合的方式去编写代码。
抽象工厂模式
抽象工厂模式与工厂方法模式的区别就在于创建产品对象的复杂程度上,如果一个产品对象由许多小对象组成,并且这些小对象可以用系列划分,我们一次只消费其中一个系列,那么我们这时候就可以使用抽象工厂了。
由于刚从三亚游玩归来,所以下面我们举一个 旅游消费平台的例子吧。假如平台上对去各地的旅游产品都有套餐服务,我们就把某地的套餐产品看作一个复杂对象,分为三个系列:
1. 豪华系列
2. 舒适系列
3. 经济系列
下面我们就来逐一分析一下:
抽象工厂类
public abstract class AbstractFactory { public abstract Hotel GenerateHotel(); public abstract Ticket GenerateTicket(); public abstract TrafficTool GenerateTrafficTool(); } |
工厂实现类
工厂的实现类,通常用来管理产品簇,在本例中3类套餐都要生成自己对应的酒店,门票和交通工具。
豪华系列
public class LuxuryFactory extends AbstractFactory { @Override public Hotel GenerateHotel() { // TODO Auto-generated method stub return 香格里拉类(一个具体酒店产品类,需要定义); //省略 } @Override public Ticket GenerateTicket() { // TODO Auto-generated method stub return 天涯海角类(一个具体景点产品类,需要定义); //省略 } @Override public TrafficTool GenerateTrafficTool() { Return 飞机票(一个具体景点交通产品类,需要定义); } } |
舒适系列
public class ComfortFactory extends AbstractFactory { @Override public Hotel GenerateHotel() { // TODO Auto-generated method stub return 银泰大酒店 ; //省略 } @Override public Ticket GenerateTicket() { // TODO Auto-generated method stub return 亚龙湾; } @Override public TrafficTool GenerateTrafficTool() { Return 火车票; } } |
经济系列
public class ComfortFactory extends AbstractFactory { @Override public Hotel GenerateHotel() { // TODO Auto-generated method stub return 7天快捷酒店; //省略 } @Override public Ticket GenerateTicket() { // TODO Auto-generated method stub return 公用海滩; //省略 } @Override public TrafficTool GenerateTrafficTool() { Return 汽车票; } } |
抽象产品类
public interface Hotel { getName(); } |
public interface Ticket { getName(); } |
public interface TrafficTool { getName(); } |
产品实现类
我们就以酒店为例,其他类似实现即可
//香格里拉 public class Shangri-la implements Hotel { public void getName () { System.out.println("香格里拉"); } } |
public class InTimeHotel implements Hotel { @Override public void getName () { // TODO Auto-generated method stub System.out.println("银泰大酒店"); } } |
………….
……………..
………………………….
调用
public class Mytest { public static void main(String[] args) { // TODO Auto-generated method stub AbstractFactory factory = new LuxuryFactory(); Hotel hotel = factory.generateHotel(); Ticket ticket = factory.generateTicket(); TrafficTool trafficTool = factory.generatetrafficTool(); } } |
总结
总的来说,工厂方法就是把实例化的具体实现过程从客户端代码中分离出来,让客户对实例化哪个对象并不关心,他只知道是把一个接口进行了实例化。这样大大增加了代码的灵活性,便于日后维护。
关于抽象工厂的总结 自我总结: 推开上面例子,我们设想一个场景:我们的套装的分为上衣和裤子,上衣和裤子又都有三种用途分类。那么: 抽象工厂,一般应用于抽象产品类中,某些属性是其他对象,就好象套装类分成三种用途(晚会,工作,休闲),那么抽象套装类就有了 3个簇分类了 ,那么抽象工厂中就应该定义getCoat()和getTrousier()两个抽象方法,以不同簇分类创建抽象工厂,有几个簇就建立几个具体工厂,我们还需要定义裤子抽象类和上衣抽象类就可以了。 书面总结: 工厂管理的是产品簇的分类,每一簇产品对应一个工厂,工厂方法对应着不同产品。该模式主要解决“系列对象”的需求变化。(某些产品需要增加一个系列...比如某个车品牌要增加一个系列车型<运动形>) 使用条件: 1. 系统中有多个产品簇,而系统一次只可能消费其中一簇产品 2. 通常在实际应用中下,在同一工厂中创建的产品他们内部都会有一些联系,所以我们才会把他们绑定在一起。
|
优点:
1. 实例化 代码集中,方便维护。
2. 针对接口编程,不针对实现,使代码有弹性,便于扩展。
关于抽象工厂和工厂方法
抽象工厂:
当要创建产品家族和想让创建的相关产品集合起来时使用。(把上衣和裤子集合起来)。
使用:
把产品家族内的每种产品作为抽象工厂的抽象接口。
工厂方法:
不知道需要实现那些具体类时使用,或者专用于客户端和创建实例的解耦。
区别:
工厂方法只需要创建一个产品
抽象方法需要创建一个产品家族其中可能有许多产品类。