Java设计模式:四、工厂模式

来源:互联网 发布:钢琴曲 知乎 编辑:程序博客网 时间:2024/06/15 20:22

工厂模式


也许有一些地方写的不够明确,如有错误,请各位大神指出。下面是从HeadFirst设计模式学习中,做的笔记:

HeadFirst设计模式工厂模式笔记

一、简单工厂模式

传统的生成对象方式为new形式,如果一个接口有多个不同的实现类,根据不同的类型new不同的对象,常见的形式为if语句或switch语句来new对象。比如:推送微信消息,有一个抽象的实体类:SendMsg,其中有一个抽象方法为sendMsg()。给微信推送消息,可以推送模板消息,也可以推送图文消息。暂时有这两个子类。所以,类的基本形式如下:

public abstract class SendMsg {    public abstract void sendMsg();    //other method...}public class SendTempMsg extends SendMsg {    public void sendMsg(){        //发送模板消息代码    }}public class SendCustomerMsg extends SendMsg {    public void sendMsg(){        //推送图文消息代码    }}

上面是对实现类的一个定义。如果要使用,传统方式如下:

public class Test {    public static void main(String[] args){        int type = 1;        SendMsg sendMsg;        switch (type) {            case: 1                sendMsg = new SendTempMsg();                break;            case: 2                sendMsg = new SendCustomerMsg();                break;        }        sendMsg.sendMsg();    }}

简单工厂模式,基本是将new这一部分代码移动到了一个工厂类中。下面定义工厂类:

public class SendMsgFactory {public static SendMsg createSendMsg(int type) {SendMsg sendMsg;switch (type) {case: 1sendMsg = new SendTempMsg();case: 2sendMsg = new SendCustomerMsg();defaults:throw new IllegalArguments("不支持创建其他类型");}return sendMsg;}}

使用类:

public class Test {public static void main(String[] args) {SendMsg sendMsg = SendMsgFactory.createSendMsg(1);sendMsg.sendMsg();}}

上面形式便是简单工厂模式。好像简单工厂和传统方式并没有什么区别,只是把一部分代码移动到了一个单独的类中。但是,使用简单工厂方法模式以后,会发现,使用者完全不知道内部是如何实现的。只知道通过工厂可以创建一个推送消息的类。所以如果后期对子类进行增加或者删除时,使用者完全不知道。但是如果使用传统形式,使用者一看便知道,有两个推送消息的类,而且紧密的与这些类耦合在了一起,假如有一天不需要其中一个了,把它移除了,使用者也必须去把它移除。这样耦合度就比较高了。

二、工厂方法模式

定义:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法的目的是将类的实例化推迟到子类。

大致类图如下:


温习工厂模式,是由于目前手上正好有一个任务,可以使用到工厂模式,所以借此机会,再熟悉熟悉工厂模式。

任务的背景大概是:

将称重商品的称重码导出为数据格式为指定格式的txt文件。目前的任务只支持导出一种格式,即DHTMA07格式。(格式为数据格式,不是导出后文件的格式,比如导出xml形式的txt文件,比如导出json形式的txt文件。为了方便,下面的例子以xml格式和json格式来举例。)

使用传统的方式实现:

public class PluFile {public PluData buildJsonPluData(){//...封装格式为json形式的数据}public PluData buildXmlPluData(){//...封装格式为xml形式的数据}public void buildFile(PluData data){//...将封装好的格式数据写入到一个本地文件中}}public class PluFileTest {public static void main(String[] args) {PluFile pluFile = new PluFile();PluData pluData = new PluData();String type = "json";switch (type) {case "json":pluData = pluFile.buildJsonPluData();case "xml":pluData = pluFile.buildXmlPluData();default:throw new IllegalArgumentsException("不支持的格式");}pluFile.buildFile(pluData);}}

上面是不适用工厂方法模式,测试类相当于客户端。PluFile直接暴露了其内部实现。这种方式是不容易扩展的。根据Effective Java中提到的,使类和成员的可访问性最小化,一旦类的成员暴露在外边,被多个地方调用,后期如有修改,将会变得很麻烦。而且客户端需要时时去关心它的内部实现。比如现在的新增了一个需求,导出格式为properties形式的txt文件。在服务端不仅要新增新建properties形式的,在客户端还要新增case语句。所以,这种方式虽然能实现功能,但并不是最好的实现方式。如果使用工厂方法模式:

/** * 产品类。让具体的产品继承它,实现对应的格式 **/public abstract class PluFile {public abstract PluData buildData();public void buildFile(PulData pluData) {//将对应的格式写入到本地txt文件中}}public class JsonPluFile extends PluFile{public PluData buildData (){//封装格式为json的格式}}public class XmlPluFile extends PluFile {public PluData buildData (){//封装格式为xml的格式}}/** * 产品创建工厂。具体的产品,到具体的工厂类下创建,写成抽象类的原因是,可以将产品的一系列相同的操作放在一起。 **/public abstract class PluFileFactory {public abstract PluFile createPluFile();public static PluFileFactory createFactoryByType(String type) {    switch (type) {      case "json":        return new JSONPluFileFactory();        case "xml":        return new XMLPluFileFactory();      default:        throw new IllegalArgumentException("不支持创建的格式");    }  }  public void createPluFileAndTotxt(List<ShopSku> shopSkuList) throws IOException, ShopSkuException {    PluFile pluFile = createPluFile();    pluFile.buildFile(pluFile.buildData());  }}/** * 创建JSON形式的产品 **/public class JsonPluFileFactory extends PluFileFactory {public PluFile createPluFile (){return new JsonPluFile();}}/** * 创建XML形式的产品 **/public class XmlPluFileFactory extends XmlFileFactory {public PluFile createPluFile (){return new XmlPluFile();}}
public class PluFileTest {public static void main(String[] args) {String type = "json";PluFileFactory.createFactoryByType(type).createPluFileAndTotxt();}}

使用工厂方法模式,它的好处是容易扩展。而且客户端并不知道其内部实现,如果后期扩展格式,客户端也不用关心具体如何实现,只要传入一个对应的格式,得到对应的结果即可。


三、抽象工厂模式




原创粉丝点击