23种设计模式之工厂方法模式、抽象工厂模式

一、简单工厂模式(静态工厂方法模式)

1.1 定义

定义一个工厂类,根据传入的参数不一样返回不一样的实例,被建立的实例具备共同的父类或接口。23种设计模式并不包括简单工厂模式,它更像一种编程习惯。编程

1.2 模式结构

简单工厂模式由三部分组成:设计模式

  • 工厂类(Creator)角色:担任这个角色的是简单工厂模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客户端的直接调用下建立产品对象。
  • 抽象产品(AbstractProduct)角色:担任这个角色的类是由简单工厂模式所建立的对象的父类,或它们共同拥有的接口。
  • 具体产品(ConcreteProduct)角色:简单工厂模式所建立的任何对象都是这个角色的实例。
1.3 实例

1.3.1 电视机父类TVbash

public abstract class TV {
    abstract void openTV();
}
复制代码

1.3.2 海尔电视机和长虹电视机分别继承TVide

public class HaierTV extends TV {
    public void openTV() {
        System.out.println("open haier TV");
    }
}
复制代码
public class ChanghongTV extends TV {
    public void openTV() {
        System.out.println("open changhong TV");
    }
}
复制代码

1.3.3 工厂类工具

public class Factory {

    public static TV watchTV(String type) throws Exception {
        if (type.equals("Haier")) {
            return new HaierTV();
        } else if (type.equals("Changhong")) {
            return new ChanghongTV();
        } else {
            throw new Exception();
        }
    }
}
复制代码

1.3.4 客户端调用ui

public class Test {
    
    public static void main(String[] args) throws Exception {
        TV tv = Factory.watchTV("Haier");
        tv.openTV();
    }
}
复制代码
1.4 适用场景
  • 工厂类负责建立的对象比较小。
  • 客户端只关心传入工厂类的参数,不关心对象的建立过程。
1.5 在JDK中的应用

Calendar.class中的部分源码:spa

private static Calendar createCalendar(TimeZone zone,
                                       Locale aLocale)
{
    CalendarProvider provider =
        LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                             .getCalendarProvider();
    if (provider != null) {
        try {
            return provider.getInstance(zone, aLocale);
        } catch (IllegalArgumentException iae) {
            // fall back to the default instantiation
        }
    }

    Calendar cal = null;

    if (aLocale.hasExtensions()) {
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype != null) {
            switch (caltype) {
            case "buddhist":
            cal = new BuddhistCalendar(zone, aLocale);
                break;
            case "japanese":
                cal = new JapaneseImperialCalendar(zone, aLocale);
                break;
            case "gregory":
                cal = new GregorianCalendar(zone, aLocale);
                break;
            }
        }
    }
    if (cal == null) {
        // If no known calendar type is explicitly specified,
        // perform the traditional way to create a Calendar:
        // create a BuddhistCalendar for th_TH locale,
        // a JapaneseImperialCalendar for ja_JP_JP locale, or
        // a GregorianCalendar for any other locales.
        // NOTE: The language, country and variant strings are interned.
        if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
            cal = new BuddhistCalendar(zone, aLocale);
        } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                   && aLocale.getCountry() == "JP") {
            cal = new JapaneseImperialCalendar(zone, aLocale);
        } else {
            cal = new GregorianCalendar(zone, aLocale);
        }
    }
    return cal;
}
复制代码
1.6 优缺点

1.6.1 优势设计

  • 工厂类含有必要的判断逻辑,能够决定在何时建立哪个产品类的实例,客户端能够免除直接建立产品对象的责任,而仅仅“消费”产品;简单工厂模式经过这种作法实现了对责任的分割,它提供了专门的工具类用于建立对象。
  • 客户端无须知道所建立的具体产品类的类名,只须要知道产品类所对应的参数便可,对应一些复杂的类名,经过简单工厂模式能够减小使用者的记忆量。
  • 经过引入配置文件,能够在不修改任何客户端代码的状况下更换和增长新的具体产品类,在必定程度上提升了系统的灵活性。
  • 当须要引入新的产品是不须要修改客户端的代码,只须要添加相应的产品类并修改工厂类就能够了,因此说从产品的角度上简单工厂模式是符合“开-闭”原则的。

1.6.2 缺点code

  • 因为工厂类集中了全部产品建立逻辑,工厂类通常被咱们称做“全能类”或者“上帝类”,由于全部的产品建立它都完成,这看似是好事,但仔细想一想是有问题的。这样一旦不能正常工做,整个系统都要受到影响。
  • 系统扩展困难,一旦添加新产品就要修改工厂逻辑,在产品类型较多时,有可能形成工厂逻辑过于复杂,不利于系统的扩展和维护。因此说从工厂的角度来讲简单工厂模式是不符合“开-闭”原则的。
  • 因为使用静态工厂方法,形成工厂角色没法造成基于继承的等级结构。

二、工厂方法模式(虚拟构造器模式、多态工厂模式)

2.1 定义

工厂父类负责定义建立产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样作的目的是将产品类的实例化操做延迟到工厂子类中完成,即经过工厂子类来肯定究竟应该实例化哪个具体产品类。orm

2.2 模式结构

工厂方法模式由四部分组成:

  • 抽象工厂(AbstractCreater)角色:担任这个角色的是工厂方法模式的核心,与调用者直接交互用来提供产品。任何在模式中建立对象的工厂类必须继承或者实现这个接口。
  • 具体工厂(ConcreteCreator)角色:担任这个角色的是实现了抽象工厂接口的具体实现类。具体工厂角色含有与应用密切相关的逻辑,而且受到应用程序的调用以建立产品对象。
  • 抽象产品(AbstractProduct)角色:工厂方法模式所建立的对象的超类。主要目的是定义产品的规范,全部的产品实现都必须遵循这些规范。
  • 具体产品(ConcreteProduct)角色:实现了抽象产品角色所声明的接口,工厂方法所建立的每个对象都是某个具体产品角色的实例。
2.3 实例

2.3.1 电视机父类TV

public abstract class TV {
    abstract void openTV();
}
复制代码

2.3.2 海尔电视机和长虹电视机分别继承TV

public class HaierTV extends TV {
    public void openTV() {
        System.out.println("open haier TV");
    }
}
复制代码
public class Changhong extends TV {
    public void openTV() {
        System.out.println('open changhong TV');
    }
}
复制代码

2.3.3 抽象工厂类

public abstract class Factory {
    public abstract TV watchTV();
}
复制代码

2.3.4 具体工厂类

public class HaierFactory extends Factory {
    public TV watchTV() {
        return new HaierTV();
    }
}
复制代码
public class ChanghongFactory extends Factory {
    public TV watchTV() {
        return new ChanghongTV();
    }
}
复制代码

2.3.5 客户端调用

public class Test {
    public static void main(String[] args) throws Exception {
        Factory factory = new HaierFactory();
        TV tv = factory.watchTV();
        tv.openTV();
    }
}
复制代码
2.4 适用场景
  • 客户端不须要知道它所场景的对象的类,只须要知道建立具体产品的工厂类。
  • 客户端能够经过子类来指定建立对应的对象。
2.5 优缺点
  • 工厂方法用来建立客户所须要的产品,同时还向客户隐藏了哪一种具体产品类将被实例化这一细节,用户只须要关心所需产品对应的工厂,无须关心建立细节。
  • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它可以使工厂能够自主肯定建立何种产品对象,而如何建立这个对象的细节则彻底封装在具体工厂内部。
  • 在系统加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其余的具体工厂和具体产品。这样系统的可扩展性变得良好,彻底符合“开-闭“原则。

三、抽象工厂模式(Kit模式)

3.1 定义

提供一个建立一系列相关或相互依赖对象的接口,而无须指明它们具体的类。

3.2 产品族和等级等级结构
  • 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,取子类有海尔电视机、长虹电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构。
  • 产品族:在抽象工厂模式中,产品族是指同一个工厂生产的,位于不一样产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

3.3 模式结构

抽象工厂模式和工厂方法模式相似都是四部分组成的,不一样的是,抽象工厂模式中具体工厂再也不是只建立一种产品,一个具体的工厂能够建立一个产品族的产品。

3.4 实例

3.4.1 电视机父类TV

public abstract class TV {
    abstract void openTV();
}
复制代码

3.4.2 海尔电视机和长虹电视机分别继承TV

public class HaireTV extends TV {
    public void openTV() {
        System.out.println("open haire TV");
    }
}
复制代码
public class ChanghongTV extends TV {
    public void openTV() {
        System.out.println('open changhong TV');
    }
}
复制代码

3.4.3 冰箱父类Refrigerator

public abstract class Refrigerator {
    abstract void openRefrigerator();
}
复制代码

3.4.4 海尔冰箱和长虹冰箱分别继承Refrigerator

public class HaierRefrigerator extends Refrigerator {
    public void openRefrigerator() {
        System.out.println("open haier refrigerator");
    }
}
复制代码
public class ChanghongRefrigerator extends Refrigerator {
    public void openRefrigerator() {
        System.out.println("open changhong refrigerator");
    }
}
复制代码

3.4.5 抽象工厂类,定义同一族产品的两个不一样等级结构的产品结构

public abstract class Factory {
    public abstract TV watchTV();
    public abstract Refrigerator takeThings();
}
复制代码

3.4.6 具体工厂类

public class HaierFactory extends Factory {
    public TV watchTV() {
        return new HaierTV();
    }

    public Refrigerator takeThings() {
        return new HaierRefrigerator();
    }
}
复制代码
public class ChanghongFactory extends Factory {
    public TV watchTV() {
        return new ChanghongTV();
    }
    
    public Refrigerator takeThings() {
        return new ChanghongRefrigerator();
    }
}
复制代码

3.4.7 客户端调用

public class Test {

    public static void main(String[] args) throws Exception {
        Factory factory = new HaierFactory();
        TV tv = factory.watchTV();
        tv.openTV();
        Refrigerator refrigerator = factory.takeThings();
        refrigerator.openRefrigerator();
    }
}
复制代码
3.5 适用场景
  • 一个系统不该当依赖于产品类实例如何被建立、组合和表达的细节,这对于全部形态的工厂模式都是重要的。
  • 系统的产品有多于一个的产品族,而系统只消费群体某一族的产品。
  • 同属于同一产品族的产品是在一块儿使用的,这一约束必须在系统的设计中体现出来。 *系统提供一个产品类的库,全部的产品以一样的接口出现,从而使客户端不依赖与实现。
3.6 优缺点

3.6.1 优势

  • 抽象工厂模式隔离了具体类的生成,使得客户不须要知道什么被建立。因为这种隔离,更换一个具体工厂就变得相对容易。全部的具体工厂都实现了抽象工厂中定义的那些公共接口,所以只需改变具体工厂的实例,就能够在某种程序上改变整个系统的行为。另外,应用抽象工厂模式能够实现高内聚低耦合的设计目的。
  • 当一个产品族中的多个对象被设计成一块儿工做时,它可以保证客户端始终只使用同一个产品族中的对象。这对一些须要根据当前环境来决定其行为的软件系统来讲,是一种很是使用的设计模式。
  • 增长新的具体工厂和产品族很方便,无须改动其余,符合“开闭”原则。

3.6.2 缺点

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是由于在抽象工厂角色中规定了全部可能被场景的产品集合,要支持新种类的产品就意味着要对接口进行扩展,而这将涉及到对抽象工厂角色及其全部子类的修改,显然带来较大的不便。
  • 开闭原则的倾斜性(增长新的工厂和产品族容易,增长新的产品等级结构麻烦)。

特别声明:一、如若文中有错之处,欢迎大神指出。 二、文章是参考网上一些大神的文章,本身整理出来的,如如有侵权,可联系我删除。

相关文章
相关标签/搜索