Skip to content

Latest commit

 

History

History
298 lines (207 loc) · 8.59 KB

2-工厂模式.md

File metadata and controls

298 lines (207 loc) · 8.59 KB

一般情况下,工厂模式分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。不过,在 GoF 的《设计模式》一书中,它将简单工厂模式看作是工厂方法模式的一种特例,所以工厂模式只被分成了工厂方法和抽象工厂两类。

简单工厂(Simple Factory)

首先,简单工厂模式不属于23种GOF四人组(Gang of Four)设计模式,简单工厂一般分为:普通简单工厂、多方法简单工厂、静态方法简单工厂。

普通

就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。

public interface Sender {  
    public void Send();  
}  

public class MailSender implements Sender {  
    @Override  
    public void Send() {  
        System.out.println("this is mailsender!");  
    }  
}  

public class SmsSender implements Sender {  
  
    @Override  
    public void Send() {  
        System.out.println("this is sms sender!");  
    }  
}  

public class SendFactory {  
  
    public Sender produce(String type) {  
        if ("mail".equals(type)) {  
            return new MailSender();  
        } else if ("sms".equals(type)) {  
            return new SmsSender();  
        } else {  
            System.out.println("请输入正确的类型!");  
            return null;  
        }  
    }  
}

多个方法

是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

//将上面的代码做下修改,改动下SendFactory类就行,如下:

public class SendFactory {  
   public Sender produceMail(){  
        return new MailSender();  
    }  
      
    public Sender produceSms(){  
        return new SmsSender();  
    }  
}

多个静态方法

//将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

public class SendFactory {  
      
    public static Sender produceMail(){  
        return new MailSender();  
    }  
      
    public static Sender produceSms(){  
        return new SmsSender();  
    }  
}

工厂方法(Factory Method)

简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

public interface Sender {  
    public void Send();  
}  

public class MailSender implements Sender {  
    @Override  
    public void Send() {  
        System.out.println("this is mailsender!");  
    }  
}  

public class SmsSender implements Sender {  
  
    @Override  
    public void Send() {  
        System.out.println("this is sms sender!");  
    }  
}  

public class SendMailFactory implements Provider {  
      
    @Override  
    public Sender produce(){  
        return new MailSender();  
    }  
}  

public class SendSmsFactory implements Provider{  
  
    @Override  
    public Sender produce() {  
        return new SmsSender();  
    }  
}  

public interface Provider {  
    public Sender produce();  
}  

public class Test {  
  
    public static void main(String[] args) {  
        Provider provider = new SendMailFactory();  
        Sender sender = provider.produce();  
        sender.Send();  
    }  
}

其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!

工厂方法分4个组件:

Product:定义工厂方法所创建的对象的接口,也就是实际需要使用的对象的接口。

ConcreteProduct:具体的 Product 接口的实现对象。

Creator:创建器,声明工厂方法,工厂方法通常会返回一个 Product 类型的实例对象,而且多是抽象方法。也可以在Createor里面提供工厂方法的默认实现,让工厂方法返回一个缺省的 Product 类型的实例对象。(对应上面的SendSmsFactory、SendMailFactory)

ConcreteCreator:具体的创建器对象,覆盖实现 Creator 定义的工厂方法,返回具体的 Product 实例。

抽象工厂(Abstract Factory)

假设目前你的程序里面有两个对象,苹果(apple)和香蕉(banana),那么你使用工厂模式就已经足够了,因为她们属于同一个品类,都属于水果,如果在添加一个菠萝产品,也只需要把菠萝加入到你的水果工厂里面就够了。

但是如果你程序里面有四个对象,苹果汁,苹果派,香蕉汁,香蕉派,这四个对象正好有明确的层级关系,可以抽象为两个层级,苹果,香蕉,或者果汁,派。这时候工厂模式明显已经不适用了,因为工厂模式是对象都实现了同一个接口,这时候就可以使用抽象工厂模式了。

就是把对象抽象一下,把这四个对象抽象为两个接口,一个果汁接口,一个派的接口。然后再设计一个抽象的工厂(抽象类)abstractFactory,里面生产抽象的对象(也就是接口)Juice,Pie,单看这个结构就是一个工厂模式,但是我们要用生产的是对象而不是接口。所以我们还需要两个具体工厂:

一个AppleFactory继承abstractFactory,实现生成Pie的方法和生成Juice的方法,实际上就是生成对象AppleJuice和ApplePie,一个BananaFactory继承abstractFactory,实现生成Pie的方法和生成Juice的方法,实际上就是生成对象BananaJuice和BananaPie,

这样的话,对于调用者来说,我在开发过程中,只需要知道我操作的对象是Pie或者是Juice就够了,这样降低了耦合。

package abstractFactory;
public class Test {
    public static void main(String args[]){
        AbstractFactory factory1 = new AppleFactory();
        factory1.createJuice().desc();
        factory1.createPie().desc();
        //假设我们之前需要的是applePie和appleJuice对象,现在需要换成bananaPie和BananaJuice对象
        //我们只需要替换对应的实现工厂(把new AppleFactory换成new BananFactory就可以了,耦合比较低)
        AbstractFactory factory2 = new BananaFactory();
        factory2.createJuice().desc();
        factory2.createPie().desc();
    }
}

// 下面是抽象工厂,生产对象的抽象。
package abstractFactory;
public abstract class AbstractFactory {
    abstract Juice createJuice();
    abstract Pie createPie();
}

// 下面是具体工厂两个
package abstractFactory;
public class AppleFactory extends AbstractFactory{

    @Override
    Juice createJuice() {
        return new AppleJuice();
    }

    @Override
    Pie createPie() {
        return new ApplePie();
    }
}

package abstractFactory;
public class BananaFactory extends  AbstractFactory{
    @Override
    Juice createJuice() {
        return new BananaJuice();
    }

    @Override
    Pie createPie() {
        return new BananaPie();
    }
}

// 下面是对象抽象出来的接口两个
package abstractFactory;
public interface Juice {
    public void desc();
}
package abstractFactory;
public interface  Pie {
    public void desc();
}

// 最后是我们要生产的四个对象。
package abstractFactory;
public class AppleJuice implements Juice {

    @Override
    public void desc() {
        System.out.println("苹果汁.");
    }
}

package abstractFactory;
public class ApplePie implements Pie {
    @Override
    public void desc() {
        System.out.println("苹果派");
    }
}

package abstractFactory;
public class BananaJuice implements Juice {
    @Override
    public void desc() {
        System.out.println("香蕉汁.");
    }
}

package abstractFactory;

public class BananaPie implements Pie {
    @Override
    public void desc() {
        System.out.println("香蕉派");
    }
}

组件

  • 抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口。
  • 实现成接口
  • 使用工厂方法

抽象工厂模式的优缺点

优点:

  • 分离接口和实现
  • 使得切换产品簇变得容易

缺点:

  • 不太容易扩展新的产品
  • 容易造成类层次复杂

参考

23种设计模式详解 - 枫树湾河桥 - 博客园