工厂方法模式和抽象工厂模式类图有什么区别.可有高手

工厂方法模式和抽象工厂模式的区别 - ITeye问答
看了一些网上的例子,头有点晕,感觉好象差不多,
可能是我看的不够细,
但是还是没办法理解这2钟模式的区别,
和用在什么地方
大家帮忙问题补充:上面讲的是抽象工厂,我想知道他们的分别,我想要真正了解的人告诉我他的理解是什么,而不是网上GOOGLE,出来
2楼说的在ioc中添加工厂有点不理解
抽象工厂模式是让工厂和依赖工厂的子类全部依赖一个接口或者抽象类,因为抽象代表这稳定,这样可以很容易的遵循oo中比较著名的开放关闭原则,设计出来的系统、框架或者程序很富有弹性和扩展能力(这句话有点大概的意思,没有具体的)
网上搜一句话,不知道对还是错
其实这两者的区别,GOF的书上说得很清楚。工厂方法采用的是类继承机制(生成一个子类,重写该工厂方法,在该方法中生产一个对象)。而抽象工厂采用的是对象组合机制,专门定义“工厂”对象来负责对象的创建。对象组合的方式就是把“工厂”对象作为参数传递。
如果是对的,能不能稍微帮我解释下,我看是懂非懂的,最好能用白话文,例子好象都差不多
采纳的答案
工厂模式是:定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到子类。
它有个特点,就是通常工厂的类层次与产品的类层次几乎是一样的树。如果说工厂是你的影子,你就是产品了。在你平时未用到模式的时候,你需要什么就new一个,这种情况就好比你躺在地上,人影合一了。那什么时候需要工厂模式呢。看看定义:“使一个类的实例化延迟到子类”,这个是关键,当你有必要延迟实例化的时候才需要用工厂模式。那什么情况下要延迟呢,在单例模式中有惰性单例(就是单例那个静态属性)……等等,就是一开始你还不适合立刻就创建该对象,你还需要一些资源或其它准备工作。整个系统的运行不像单个程序那样,系统需要很多资源和多方面的协同工作。
抽象工厂是:提供一个创建一系列相关或相互依赖对象的接口,而无虚指定他们的具体类。
抽象工厂比工厂模式复杂的多。如果楼主说他们像可能是他们都叫工厂,都生成产品,都是接口型设计模式。但是我觉得他们是两个不同的设计模式。首先他们的目的是不同的。工厂是为了“延迟创建”,而抽象工厂是提供一系列的接口,是为了组织创建对象的灵活性,避免重复,避免耦合低内聚。
设计模式本身语言晦涩难懂,这个抽象工厂我也是没次都看着头昏眼花^_^,举个运用他的场景:
1。你有两台单色打印机,一台黑白墨的,一台彩墨的。
2。你有两种文件要打,一种讲演搞,一种图片
3。要求是讲演稿如果是有图就打黑白的,没图打彩色的,照片有字的就打黑白的,没字就打彩色的。
class Print{
void doTalk(){
//non-color
void doPicture(){
//non-color
上面的这个场景就是可以运用抽象工厂来重构的。
public abstract class AbsFactory{
&&& abstract TalkPrint getTalkPrint(); //打讲演稿
&&& abatract PicPrint getPicPrint();&& //打图片的
}
public class ColorFactory extends AbsFactory{
&&& TalkPrint getTalkPrint(){
&&&&&& //彩色讲演稿打印
&&& }
&&& PicPrint getPicPrint(){
&&&&&& //彩色图片打印
&&& }
}
public class NonColorFactory extends AbsFactory{
&&& TalkPrint getTalkPrint(){
&&&&&&&& //黑白讲演稿打印
&&& }
&&& PicPrint getPicPrint(){
&&&&&&&& //黑白图片打印
&&& }&
public abstract class TalkPrint{
&& //抽象的讲演稿打印
}
public class colorTalkPrint extends TalkPrint{
&& //彩色讲演稿打印
}
public class noncolorTalkPrint extends TalkPrint{
&& //黑白讲演稿打印
}
public abstract class PicPrint{
&& //抽象的图片打印
}
public class colorPicPrint extends PicPrint{
&& //彩色图片打印
}
public class noncolorPicPrint extends PicPrint{
&& //黑白图片打印
}
进一步解释这个场景,就是当你做相似的工作又多种选择的时候,可以考虑用抽象工厂。
这里你要打印各种文件是一组相似的工作,打印有彩色、黑白等针对打印的不同要求。
这里仅仅举了一个方面的例子。
我们可以看出,虽然抽象工厂和工厂在代码形式上很相似,甚至抽象工作可以有工厂来拓展,但是他们的出发点是不一样的。
在搞单例模式的时候我们针对多线程拓展了为“双重检查模式”,那是同一个场景同一个任务,跟这里是不一样的。
关于单例模式,我有笔记留在我的博客,欢迎大家来一起讨论:
/blog/214675
一楼很善于google嘛。。。
工厂模式和抽象工厂模式的区别:
楼主不妨可以这么理解,抽象工厂模式就是ioc之后的工厂模式
呵呵,也就是说抽象工厂模式就是在工厂模式的基础上添加啦spring框架
具体就是这个意思,抽象工厂模式是让工厂和依赖工厂的子类全部依赖一个接口或者抽象类,因为抽象代表这稳定,这样可以很容易的遵循oo中比较著名的开放关闭原则,设计出来的系统、框架或者程序很富有弹性和扩展能力
不知道这么说楼主明白否?
工厂模式定义:提供创建对象的接口.
为何使用?
工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。
为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑实用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
我们以类Sample为例, 如果我们要创建Sample的实例对象:
Sample sample=new Sample();
可是,实际情况是,通常我们都要在创建sample实例时做点初始化的工作,比如赋值 查询数据库等。
首先,我们想到的是,可以使用Sample的构造函数,这样生成实例就写成:
Sample sample=new Sample(参数);
但是,如果创建sample实例时所做的初始化工作不是象赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那你的代码很难看了(就需要Refactor重整)。
为什么说代码很难看,初学者可能没有这种感觉,我们分析如下,初始化工作如果是很长一段代码,说明要做的工作很多,将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有背于Java 面向对象的原则,面向对象的封装(Encapsulation)和分派(Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“ 封装”起来(减少段和段之间偶合联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。
在本例中,首先,我们需要将创建实例的工作与使用实例的工作分开, 也就是说,让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去。
这时我们就需要Factory工厂模式来生成对象了,不能再用上面简单new Sample(参数)。还有,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.现在Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下:
Sample mysample=new MySample();
Sample hissample=new HisSample();
随着项目的深入,Sample可能还会"生出很多儿子出来", 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.
但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了.
工厂方法
你会建立一个专门生产Sample实例的工厂:
public class Factory{
  public static Sample creator(int which){
  //getClass 产生Sample 一般可使用动态类装载装入类。
  if (which==1)
    return new SampleA();
  else if (which==2)
    return new SampleB();
}
那么在你的程序中,如果要实例化Sample时.就使用
Sample sampleA=Factory.creator(1);
这样, 在整个就不涉及到Sample的具体子类,达到封装效果,也就减少错误修改的机会,这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易范错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,范错误可能性就越少.好象我们从编程序中也能悟出人生道理?呵呵.
使用工厂方法 要注意几个角色,首先你要定义产品接口,如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factory类,用来生成产品Sample,如下图,最右边是生产的对象Sample:
进一步稍微复杂一点,就是在工厂类上进行拓展,工厂类也有继承它的实现类concreteFactory了。
抽象工厂
工厂模式中有: 工厂方法(Factory Method) 抽象工厂(Abstract Factory).
这两个模式区别在于需要创建对象的复杂程度上。如果我们创建对象的方法变得复杂了,如上面工厂方法中是创建一个对象Sample,如果我们还有新的产品接口Sample2.
这里假设:Sample有两个concrete类SampleA和SamleB,而Sample2也有两个concrete类Sample2A和SampleB2
那么,我们就将上例中Factory变成抽象类,将共同部分封装在抽象类中,不同部分使用子类实现,下面就是将上例中的Factory拓展成抽象工厂:
public abstract class Factory{
  public abstract Sample creator();
  public abstract Sample2 creator(String name);
public class SimpleFactory extends Factory{
  public Sample creator(){
    .........
    return new SampleA
  public Sample2 creator(String name){
    .........
    return new Sample2A
public class BombFactory extends Factory{
  public Sample creator(){
    ......
    return new SampleB
  public Sample2 creator(String name){
    ......
    return new Sample2B
从上面看到两个工厂各自生产出一套Sample和Sample2,也许你会疑问,为什么我不可以使用两个工厂方法来分别生产Sample和Sample2?
抽象工厂还有另外一个关键要点,是因为 SimpleFactory内,生产Sample和生产Sample2的方法之间有一定联系,所以才要将这两个方法捆绑在一个类中,这个工厂类有其本身特征,也许制造过程是统一的,比如:制造工艺比较简单,所以名称叫SimpleFactory。
在实际应用中,工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,
我们以Jive的ForumFactory为例,这个例子在前面的Singleton模式中我们讨论过,现在再讨论其工厂模式:
public abstract class ForumFactory {
  private static Object initLock = new Object();
  private static String className = "com.jivesoftware.forum.database.DbForumFactory";
  private static ForumFactory factory =
  public static ForumFactory getInstance(Authorization authorization) {
    //If no valid authorization passed in, return null.
    if (authorization == null) {
      
    //以下使用了Singleton 单态模式
    if (factory == null) {
      synchronized(initLock) {
        if (factory == null) {
            ......
          try {
              //动态转载类
              Class c = Class.forName(className);
              factory = (ForumFactory)c.newInstance();
          }
          catch (Exception e) {
              
          }
        }
      }
    //Now, 返回 proxy.用来限制授权对forum的访问
    return new ForumFactoryProxy(authorization, factory,
                    factory.getPermissions(authorization));
  //真正创建forum的方法由继承forumfactory的子类去完成.
  public abstract Forum createForum(String name, String description)
  throws UnauthorizedException, ForumAlreadyExistsE
因为现在的Jive是通过数据库系统存放论坛帖子等内容数据,如果希望更改为通过文件系统实现,这个工厂方法ForumFactory就提供了提供动态接口:
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
你可以使用自己开发的创建forum的方法代替com.jivesoftware.forum.database.DbForumFactory就可以.
在上面的一段代码中一共用了三种模式,除了工厂模式外,还有Singleton单态模式,以及proxy模式,proxy模式主要用来授权用户对forum的访问,因为访问forum有两种人:一个是注册用户 一个是游客guest,那么那么相应的权限就不一样,而且这个权限是贯穿整个系统的,因此建立一个proxy,类似网关的概念,可以很好的达到这个效果.&
看看Java宠物店中的CatalogDAOFactory:
public class CatalogDAOFactory {
  * 本方法制定一个特别的子类来实现DAO模式。
  * 具体子类定义是在J2EE的部署描述器中。
  public static CatalogDAO getDAO() throws CatalogDAOSysException {
    CatalogDAO catDao =
    try {
      InitialContext ic = new InitialContext();
      //动态装入CATALOG_DAO_CLASS
      //可以定义自己的CATALOG_DAO_CLASS,从而在无需变更太多代码
      //的前提下,完成系统的巨大变更。
      String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS);
      catDao = (CatalogDAO) Class.forName(className).newInstance();
    } catch (NamingException ne) {
      throw new CatalogDAOSysException("
        CatalogDAOFactory.getDAO: NamingException while
          getting DAO type : \n" + ne.getMessage());
    } catch (Exception se) {
      throw new CatalogDAOSysException("
        CatalogDAOFactory.getDAO: Exception while getting
          DAO type : \n" + se.getMessage());
    return catD
CatalogDAOFactory是典型的工厂方法,catDao 是通过动态类装入器className获得CatalogDAOFactory具体实现子类,这个实现子类在Java宠物店是用来操作catalog数据库,用户可以根据数据库的类型不同,定制自己的具体实现子类,将自己的子类名给与CATALOG_DAO_CLASS变量就可以。
由此可见,工厂方法确实为系统结构提供了非常灵活强大的动态扩展机制,只要我们更换一下具体的工厂方法,系统其他地方无需一点变换,就有可能将系统功能进行改头换面的变化。
已解决问题
未解决问题结合简单示例和UML图,讲解工厂模式简单原理。
话说十年前,有一个爆发户,他家有三辆汽车(Benz(奔驰)、Bmw(宝马)、Audi(奥迪)),还雇了司机为他开车。不过,爆发户坐车时总是这样:上Benz车后跟司机说&开奔驰车!&,坐上Bmw后他说&开宝马车!&,坐上 Audi后他说&开奥迪车!&。你一定说:这人有病!直接说开车不就行了?!而当把这个爆发户的行为放到我们程序语言中来,我们发现C语言一直是通过这种方式来坐车的!幸运的是这种有病的现象在OO语言中可以避免了。下面以Java语言为基础来引入我们本文的主题:工厂模式!
工厂模式主要是为创建对象提供了接口。工厂模式按照《Java与模式》中的提法分为三类:1. 简单工厂模式(Simple Factory)2. 工厂方法模式(Factory Method)3. 抽象工厂模式(Abstract Factory)这三种模式从上到下逐步抽象,并且更具一般性。还有一种分类法,就是将简单工厂模式看为工厂方法模式的一种特例,两个归为一类。两者皆可,这本为使用《Java与模式》的分类方法。在什么样的情况下我们应该记得使用工厂模式呢?大体有两点:1.在编码时不能预见需要创建哪种类的实例。2.系统不应依赖于产品类实例如何被创建、组合和表达的细节工厂模式能给我们的OOD、OOP带来哪些好处呢??
三、简单工厂模式
这个模式本身很简单而且使用在业务较简单的情况下。一般用于小项目或者具体产品很少扩展的情况(这样工厂类才不用经常更改)。它由三种角色组成:工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,根据逻辑不同,产生具体的工厂产品。如例子中的Driver类。抽象产品角色:它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。如例中的Car接口。具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现,如例子中的Benz、Bmw类。
来用类图来清晰的表示下的它们之间的关系:
下面就来给那个暴发户治病:在使用了简单工厂模式后,现在暴发户只需要坐在车里对司机说句:&开车&就可以了。来看看怎么用代码实现的:(为方便起见,所有的类放在一个文件中,故有一个类被声明为public)
Java代码&&
abstract&class&Car{&&
&&&&private&String&&&
&&&&public&abstract&void&drive();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&Benz&extends&Car{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----go-----------------------");&&
class&Bmw&extends&Car{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----go-----------------------");&&
class&Driver{&&
&&&&public&static&Car&createCar(String&car){&&
&&&&&&&&Car&c&=&null;&&
&&&&&&&&if("Benz".equalsIgnoreCase(car))&&
&&&&&&&&&&&&c&=&new&Benz();&&
&&&&&&&&else&if("Bmw".equalsIgnoreCase(car))&&
&&&&&&&&&&&&c&=&new&Bmw();&&
&&&&&&&&return&c;&&
public&class&BossSimplyFactory&{&&
&&&&public&static&void&main(String[]&args)&throws&IOException&{&&
&&&&&&&&&&
&&&&&&&&Car&car&=&Driver.createCar("benz");&&
&&&&&&&&car.setName("benz");&&
&&&&&&&&&&&
&&&&&&&&car.drive();&&
&span&style="font-family:&courier&new,"&}&/span&&&
如果老板要坐奥迪,同理。
这便是简单工厂模式了。那么它带了了什么好处呢?首先,符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责&消费&产品(正如暴发户所为)。下面我们从开闭原则上来分析下简单工厂模式。当暴发户增加了一辆车的时候,只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。(即创建一个新的车类,继承抽象产品Car)那么 对于产品部分来说,它是符合开闭原则的&&对扩展开放、对修改关闭;但是工厂类不太理想,因为每增加一辆车,都要在工厂类中增加相应的商业逻辑和判 断逻辑,这显自然是违背开闭原则的。
而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝类坏了。正如我前面提到的简单工厂模式适用于业务简单的情况下或者具体产品很少增加的情况。而对于复杂的业务环境可能不太适应了。这就应该由工厂方法模式来出场了!!
四、工厂方法模式抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。来用类图来清晰的表示下的它们之间的关系:
话说暴发户生意越做越大,自己的爱车也越来越多。这可苦了那位司机师傅了,什么车它都要记得,维护,都要经过他来使用!于是暴发户同情他说:我给你分配几个人手,你只管管好他们就行了!于是工厂方法模式的管理出现了。代码如下:
Java代码&&
abstract&class&Car{&&
&&&&private&String&&&
&&&&public&abstract&void&drive();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&Benz&extends&Car{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----go-----------------------");&&
class&Bmw&extends&Car{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----go-----------------------");&&
abstract&class&Driver{&&
&&&&public&abstract&Car&createCar(String&car)&throws&E&&
class&BenzDriver&extends&Driver{&&
&&&&public&Car&createCar(String&car)&throws&Exception&{&&
&&&&&&&&return&new&Benz();&&
class&BmwDriver&extends&Driver{&&
&&&&public&Car&createCar(String&car)&throws&Exception&{&&
&&&&&&&&return&new&Bmw();&&
public&class&Boss{&&
&&&&public&static&void&main(String[]&args)&throws&Exception&{&&
&&&&&&&&Driver&d&=&new&BenzDriver();&&
&&&&&&&&Car&c&=&d.createCar("benz");&&&
&&&&&&&&c.setName("benz");&&
&&&&&&&&c.drive();&&
&使用开闭原则来分析下工厂方法模式。当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。(即当有新产品时,只要创建并基础抽象产品;新建具体工厂继承抽象工厂;而不用修改任何一个类)工厂方法模式是完全符合开闭原则的!
使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。当然特殊的情况,就要特殊对待了:对于系统中存在不同的产品树,而且产品树上存在产品族(下一节将解释这个名词)。那么这种情况下就可能可以使用抽象工厂模式了。
让我们来看看简单工厂模式、工厂方法模式给我们的启迪:如果不使用工厂模式来实现我们的例子,也许代码会减少很多&&只需要实现已有的车,不使用多态。但是在可维护性上,可扩展性上是非常差的(你可以想象一下添加一辆车后要牵动的类)。因此为了提高扩展性和维护性,多写些代码是值得的。
六、抽象工厂模式
先来认识下什么是产品族: 位于不同产品等级结构中,功能相关联的产品组成的家族。
图中的BmwCar和BenzCar就是两个产品树(产品层次结构);而如图所示的BenzSportsCar和BmwSportsCar就是一个产品族。他们都可以放到跑车家族中,因此功能有所关联。同理BmwBussinessCar和BenzBusinessCar也是一个产品族。可以这么说,它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。而且使用抽象工厂模式还要满足一下条件:1.系统中有多个产品族,而系统一次只可能消费其中一族产品2.同属于同一个产品族的产品以其使用。来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
Java代码&&
abstract&class&BenzCar{&&
&&&&private&String&&&
&&&&public&abstract&void&drive();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&BenzSportCar&extends&BenzCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----BenzSportCar-----------------------");&&
class&BenzBusinessCar&extends&BenzCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----BenzBusinessCar-----------------------");&&
abstract&class&BmwCar{&&
&&&&private&String&&&
&&&&public&abstract&void&drive();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&BmwSportCar&extends&BmwCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----BmwSportCar-----------------------");&&
class&BmwBusinessCar&extends&BmwCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----BmwBusinessCar-----------------------");&&
abstract&class&AudiCar{&&
&&&&private&String&&&
&&&&public&abstract&void&drive();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&AudiSportCar&extends&AudiCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----AudiSportCar-----------------------");&&
class&AudiBusinessCar&extends&AudiCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----AudiBusinessCar-----------------------");&&
abstract&class&Driver3{&&
&&&&public&abstract&BenzCar&createBenzCar(String&car)&throws&E&&
&&&&public&abstract&BmwCar&createBmwCar(String&car)&throws&E&&
&&&&public&abstract&AudiCar&createAudiCar(String&car)&throws&E&&
class&SportDriver&extends&Driver3{&&
&&&&public&BenzCar&createBenzCar(String&car)&throws&Exception&{&&
&&&&&&&&return&new&BenzSportCar();&&
&&&&public&BmwCar&createBmwCar(String&car)&throws&Exception&{&&
&&&&&&&&return&new&BmwSportCar();&&
&&&&public&AudiCar&createAudiCar(String&car)&throws&Exception&{&&
&&&&&&&&return&new&AudiSportCar();&&
class&BusinessDriver&extends&Driver3{&&
&&&&public&BenzCar&createBenzCar(String&car)&throws&Exception&{&&
&&&&&&&&return&new&BenzBusinessCar();&&
&&&&public&BmwCar&createBmwCar(String&car)&throws&Exception&{&&
&&&&&&&&return&new&BmwBusinessCar();&&
&&&&public&AudiCar&createAudiCar(String&car)&throws&Exception&{&&
&&&&&&&&return&new&AudiBusinessCar();&&
public&class&BossAbstractFactory&{&&
&&&&public&static&void&main(String[]&args)&throws&Exception&{&&
&&&&&&&&&&
&&&&&&&&Driver3&d&=&new&BusinessDriver();&&
&&&&&&&&AudiCar&car&=&d.createAudiCar("");&&
&&&&&&&&car.drive();&&
其中:BenzSportCar和BenzBusinessCar属于产品树;同理BmwSportCar和BmwBusinessCar。而BenzSportCar和BmwSportCar和AudiSportCar属于产品族。
所以抽象工厂模式一般用于具有产品树和产品族的场景下。
抽象工厂模式的缺点:如果需要增加新的产品树,那么就要新增三个产品类,比如VolvoCar,VolvoSportCar,VolvoSportCar,并且要修改三个工厂类。这样大批量的改动是很丑陋的做法。
所以可以用简单工厂配合反射来改进抽象工厂:UML图略。
Java代码&&
abstract&class&BenzCar{&&
&&&&private&String&&&
&&&&public&abstract&void&drive();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&BenzSportCar&extends&BenzCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----BenzSportCar-----------------------");&&
class&BenzBusinessCar&extends&BenzCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----BenzBusinessCar-----------------------");&&
abstract&class&BmwCar{&&
&&&&private&String&&&
&&&&public&abstract&void&drive();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&BmwSportCar&extends&BmwCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----BmwSportCar-----------------------");&&
class&BmwBusinessCar&extends&BmwCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----BmwBusinessCar-----------------------");&&
abstract&class&AudiCar{&&
&&&&private&String&&&
&&&&public&abstract&void&drive();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&AudiSportCar&extends&AudiCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----AudiSportCar-----------------------");&&
class&AudiBusinessCar&extends&AudiCar{&&
&&&&public&void&drive(){&&
&&&&&&&&System.out.println(this.getName()+"----AudiBusinessCar-----------------------");&&
class&Driver3{&&
&&&&public&static&BenzCar&createBenzCar(String&car)&throws&Exception&{&&
&&&&&&&&return&(BenzCar)&Class.forName(car).newInstance();&&
&&&&public&static&BmwCar&createBmwCar(String&car)&throws&Exception&{&&
&&&&&&&&return&(BmwCar)&Class.forName(car).newInstance();&&
&&&&public&static&AudiCar&createAudiCar(String&car)&throws&Exception&{&&
&&&&&&&&return&(AudiCar)&Class.forName(car).newInstance();&&
public&class&SimpleAndAbstractFactory&{&&
&&&&public&static&void&main(String[]&args)&throws&Exception&{&&
&&&&&&&&AudiCar&car&=&Driver3.createAudiCar("com.java.pattendesign.factory.AudiSportCar");&&
&&&&&&&&car.drive();&&
&从策略一词来看,策略模式是种倾向于行为的模式.有点类似找仗时的做战方案,一般司令员在做战前都会根据实际情况做出几套不同的方案,如果当时情况有变,就会根据相应的条件来判定用哪一套方案来替换原定方案。但无论如何替换,替换多少次,仗还是要打的。
& 举例:导出成EXCEL,WORD,PDF文件的功能,这三类导出虽然具体操作略有不同,但是大部分都相同。
策略模式与工厂模式从uml图上来说,基本一致。只是强调的封装不同。我们以工厂模式和策略模式的比较来讲解策略模式。
工厂模式我们可以做如下理解:假设有Audi的公司生产汽车,它掌握一项核心的技术就是生产汽车,另一方面,它生产的汽车是有不同型号的,并且在不同的生产线上进行组装。当客户通过销售部门进行预定后,Audi公司将在指定的生产线上为客户生产出它所需要的汽车。
策略(Strategy)模式在结构上与工厂模式类似,唯一的区别是工厂模式实例化一个产品的操作是在服务端来做的,换句话说客户端传达给服务端的只是某种标识,服务端根据该标识实例化一个对象。而策略模式的客户端传达给服务端的是一个实例,服务端只是将该实例拿过去在服务端的环境里执行该实例的方法。这就好比一个对汽车不甚了解的人去买车,他在那一比划,说要什么什么样的,销售部门根据他的这个&比划&来形成一份订单,这就是工厂模式下的工作方式。而策略模式下那个顾客就是个行家,他自己给出了订单的详细信息,销售部门只是转了一下手就交给生产部门去做了。通过两相对比,我们不难发现,采用工厂模式必须提供足够灵活的销售部门,如果用户有了新的需求,销售部门必须马上意识到这样才可以做出合适的订单。所以倘一款新车出来了,生产部门和销售部门都需要更新,对顾客来说也需要更新对新车的描述所以需要改动的地方有三处。而策略模式中的销售部门工作比较固定,它只负责接受订单并执行特定的几个操作。当一款新车出来时,只需要对服务端的生产部门和客户端的代码进行更新,而不需要更新销售部门的代码。&
技术支持: 简单工厂和策略的基础都是因为面向对象的封装与多态。他们实现的思想都是先设定一个抽象的模型并从该模型派生出符合不同客户需求的各种方法,并加以封装。
工厂模式和策略模式的区别在于实例化一个对象的位置不同,对工厂模式而言,实例化对象是放在服务端的,即放在了工厂类里面;
而策略模式实例化对象的操作在客户端,服务端的&销售部门&只负责传递该对象,并在服务端的环境里执行特定的操作。。。
工厂模式要求服务端的销售部门足够灵敏,而策略模式由于对策略进行了封装,所以他的销售部门比较傻,需要客户提供足够能区分使用哪种策略的参数,而这最好的就是该策略的实例了。
Java代码&&
abstract&class&AudiCar{&&
&&&&private&String&&&
&&&&public&abstract&void&makeCar();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&AudiA6&extends&AudiCar{&&
&&&&public&void&makeCar(){&&
&&&&&&&&System.out.println(this.getName()+"----go-----------------------");&&
class&AudiA4&extends&AudiCar{&&
&&&&public&void&makeCar(){&&
&&&&&&&&System.out.println(this.getName()+"----go-----------------------");&&
class&CarContext&{&&
&&&&AudiCar&audiCar&=&null;&&
&&&&public&CarContext(AudiCar&audiCar)&{&&
&&&&&&&&this.audiCar&=&audiC&&
&&&&public&void&orderCar(){&&
&&&&&&&&this.audiCar.makeCar();&&
public&class&SimplyFactoryAndStrategy2&{&&
&&&&public&static&void&main(String[]&args)&throws&IOException&{&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&AudiCar&car&=&new&AudiA6();&&
&&&&&&&&car.setName("a6");&&
&&&&&&&&&&
&&&&&&&&CarContext&context&=&new&CarContext(car);&&
&&&&&&&&context.orderCar();&&
abstract&class&AudiCar{&&
&&&&private&String&&&
&&&&public&abstract&void&makeCar();&&
&&&&public&String&getName()&{&&
&&&&&&&&return&&&
&&&&public&void&setName(String&name)&{&&
&&&&&&&&this.name&=&&&
class&AudiA6&extends&AudiCar{&&
&&&&public&void&makeCar(){&&
&&&&&&&&System.out.println(this.getName()+"----go-----------------------");&&
class&AudiA4&extends&AudiCar{&&
&&&&public&void&makeCar(){&&
&&&&&&&&System.out.println(this.getName()+"----go-----------------------");&&
class&CarFactroy{&&
&&&&public&static&AudiCar&createCar(String&car){&&
&&&&&&&&AudiCar&c&=&null;&&
&&&&&&&&if("A6".equalsIgnoreCase(car))&&
&&&&&&&&&&&&c&=&new&AudiA6();&&
&&&&&&&&else&if("A4".equalsIgnoreCase(car))&&
&&&&&&&&&&&&c&=&new&AudiA4();&&
&&&&&&&&return&c;&&
public&class&SimplyFactoryAndStrategy&{&&
&&&&public&static&void&main(String[]&args)&throws&IOException&{&&
&&&&&&&&&&
&&&&&&&&System.out.print("请输入您要坐的车:(A6、A4)");&&
&&&&&&&&String&carName&=&new&BufferedReader(new&InputStreamReader(System.in)).readLine();&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&AudiCar&car&=&CarFactroy.createCar(carName);&&
&&&&&&&&car.setName(carName);&&
&&&&&&&&car.makeCar();&&&&
策略模式的优缺点
& 策略模式的主要优点有:
策略类之间可以自由切换,由于策略类实现自同一个抽象,所以他们之间可以自由切换。
易于扩展,增加一个新的策略对策略模式来说非常容易,基本上可以在不改变原有代码的基础上进行扩展。
避免使用多重条件,如果不使用策略模式,对于所有的算法,必须使用条件语句进行连接,通过条件判断来决定使用哪一种算法,在上一篇文章中我们已经提到,使用多重条件判断是非常不容易维护的。
& 策略模式的缺点主要有两个:
维护各个策略类会给开发带来额外开销,可能大家在这方面都有经验:一般来说,策略类的数量超过5个,就比较令人头疼了。
必须对 客户端(调用者)暴露所有的策略类,因为使用哪种策略是由客户端来决定的,因此,客户端应该知道有什么策略,并且了解各种策略之间的区别,否则,后果很严 重。例如,有一个排序算法的策略模式,提供了快速排序、冒泡排序、选择排序这三种算法,客户端在使用这些算法之前,是不是先要明白这三种算法的适用情况? 再比如,客户端要使用一个容器,有链表实现的,也有数组实现的,客户端是不是也要明白链表和数组有什么区别?就这一点来说是有悖于迪米特法则的。
&&&&&&& 做面向对象设计的,对策略模式一定很熟悉,因为它实质上就是面向对象中的继承和多态,在看完策略模式的通用代码后,我想,即使之前从来没有听说过策略模式,在开发过程中也一定使用过它吧?至少在在以下两种情况下,大家可以考虑使用策略模式,
几个类的主要逻辑相同,只在部分逻辑的算法和行为上稍有区别的情况。
有几种相似的行为,或者说算法,客户端需要动态地决定使用哪一种,那么可以使用策略模式,将这些算法封装起来供客户端调用。
&&&&&& 策略模式是一种简单常用的模式,我们在进行开发的时候,会经常有意无意地使用它,一般来说,策略模式不会单独使用,跟模版方法模式、工厂模式等混合使用的情况比较多。
大粒度的 if --else if...可以使用 工厂+策略模式搞定。
阅读(...) 评论()

我要回帖

更多关于 抽象工厂设计模式 的文章

 

随机推荐