工厂方法模式​​​​​​​

1.简单工厂模式的不足

在简单工厂模式中,只提供了一个工厂类,该工厂类处于对产品类进行实例化的中心位置,它知道每一个产品对象的创建细节,并决定何时实例化哪一个产品类。简单模式最大的缺点是当有新产品要加入到系统中时,必须要修改工厂类,加入必要的处理逻辑,这就违背了“开闭原则”。关于简单工厂模式可查看此链接:

2.工厂方法模式结构

 2.1模式类图

工厂方法模式包含如下角色:

1.Product(抽象产品)

        抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的共同父类或接口。

2.ConcreteProduct(具体产品)

        具体产品实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,它们之间一一对应,

3.Factory(抽象工厂)

        在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,它与应用程序无关。任何在模式中创建对象的工厂类都必须实现该接口。

4.ConcreteFactory(具体工厂)

        具体工厂是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。在具体工厂类中包含与应用程序密切相关发逻辑,并且既然等候应用程序调用以创建产品对象。

3.工厂方法模式实例与解析

题目:海尔工厂(Haier)生产海尔空调(HaierAirCondition),美的工厂(Midea)生产美的空调(MideaAirCondition) 。使用工厂方法模式描述该场景,绘制类图并编程实现。

3.1类图

3.2实例代码及解释

1.抽象产品类 Airconditioning(空调类

public interface Airconditioning {

        public void play();

}

        Airconditioning作为抽象产品类它可以是一个接口也可以是一个抽象类其中包含了所有产品都具有的业务方法play().

2.具体产品类HaierACD海尔空调类

public class HaierACD implements Airconditioning{

    @Override

    public void play() {

        System.out.println("海尔空调使用中~");

    }

}

        HaierACD是抽象产品Airconditioning接口的子类它是一种具体产品实现了在Airconditioning接口中定义的业务方法paly()。

3.具体产品类MeideACD美的空调类

public class MeideACD implements Airconditioning{

    @Override

    public void play() {

        System.out.println("美的空调使用中~");

    }

}

        MeideACD是抽象产品Airconditioning的另一个子类

4.抽象工厂类AirconditioningFactory空调工厂类

public interface AirconditioningFactory {

        public Airconditioning pruduceACD();

}

        AirconditioningFactory是抽象工厂类,它可以是一个接口也可以是一个抽象类它包含了抽象的工厂方法Airconditioning pruduceACD()返回一个抽象产品Airconditioning类型的对象

5.具体工厂类HaierACDFactory海尔空调工厂类

public class HaierACDFactory implements AirconditioningFactory{

    @Override

    public Airconditioning pruduceACD() {

        System.out.println("海尔空调已生产");

        return new HaierACD();

    }

}

        HaierACDFactory是具体工厂类它是一个抽象工厂类AirconditioningFactory的子类实现了抽象工厂方法pruduceACD()在工厂方法中创建并返回一个对象的具体产品

6.具体工厂类MeideACDFactory美的工厂类

public class MeideACDFactory implements AirconditioningFactory{

    @Override

    public Airconditioning pruduceACD() {

        System.out.println("美的空调已生产");

        return new MeideACD();

    }

}

3.3辅助代码

  1. XML操作工具类XMLUtil
package factor_method_pattern;

import org.w3c.dom.*;

import javax.xml.parsers.*;

import java.io.*;



public class XMLUtil {

    public static Object getBean(){

        try {

            //创建DOM文档对象

            DocumentBuilderFactory dFactory =DocumentBuilderFactory.newInstance();

            DocumentBuilder builder = dFactory.newDocumentBuilder();

            Document doc;

            doc = builder.parse(new File("config.xml"));

            //获取包含类名的文本节点

            NodeList nl = doc.getElementsByTagName("className");

            Node classNode = nl.item(0).getFirstChild();

            String cName = classNode.getNodeValue();

            //通过类名生成实例对象并将其返回

            Class c = Class.forName(cName);

            Object obj = c.newInstance();

            return obj;

        }

        catch (Exception e){

            e.printStackTrace();

            return null;

        }

    }

}

2.配置文件config.xml

<?xml version="1.0"  ?>

<config >

<className>factor_method_pattern.MeideACDFactory</className>

</config>

3.客户端测试类Client

package factor_method_pattern;

public class Client {

    public static void main(String[] args) {

        try{

            Airconditioning acd;

            AirconditioningFactory acdfactory;

            acdfactory = (AirconditioningFactory)XMLUtil.getBean();

            acd = acdfactory.pruduceACD();

            acd.play();

        }

        catch (Exception e)

        {

            System.out.println(e.getMessage());

        }

    }

}

3.4结果及分析

如果在配置文件中将<className>节点中的内容设置为MeideACDFactory则会输出结果如下

如果在配置文件中将<className>节点中的内容设置为HaierACDFactory则会输出结果如下

如果需要增加一种新的类型的空调,如小天鹅空调,首先需要增加一个新的具体产品类XiaotianeACD,代码如下:

package factor_method_pattern;



public class XiaotianeACD implements Airconditioning{

    @Override

    public void play() {

        System.out.println("小天鹅空调使用中~");

    }

}

在对应增加一个具体工厂类XiaotianeACDFactory,代码如下:

package factor_method_pattern;



public class XiaotianeACDFactory implements AirconditioningFactory{

    @Override

    public Airconditioning pruduceACD() {

        System.out.println("小天鹅空调已生产");

        return new XiaotianeACD();

    }

}

最后修改XML配置文件,修改后的代码如下:

<?xml version="1.0"  ?>

<config >

<className>factor_method_pattern.XiaotianeACDFactory</className>

</config>

编译新增的两个类,运行客户端测试代码,结果如下:

4.工厂方法模式总结

4.1.工厂方法模式的优点

(1)在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪

种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。

(2)基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可

以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。

(3)使用工厂方法模式的另一个优点是在系统中加人新产品时,无须修改抽象工厂和

抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

4.2.工厂方法模式的缺点

(1)在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。

(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到 DOM、反射等技术,增加了系统的实现难度。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐