工厂的模式们
2016-08-09 13:51
453 查看
DIY
SimpleFactory
FactoryMethod
AbstractFactory
客户需要知道怎么去创建一款打印机,客户和打印机就紧密耦合在一起了。
为了降低耦合,就出现了工厂类。
然后,所有的打印机都继承这个类,具体产品:
再造一个工厂:
接着客户就可以直接提打印机了:
只需要先实例化一个工厂,再用工厂去生产打印机就好了。
这里用到了向上转型,eg:
但是简单工厂显然有很多弊端:
最直观的来讲,它违反了开闭原则(对扩展开放,对修改封闭)
即每当需要增加一种打印机的时候,需要修改SimpleFactory类,增加case语句。而根据开闭原则,“修改”是不合适的。
而且每次在创建打印机的时候,还需要传一个brand参数。
简单工厂模式中的工厂,虽然号称简单工厂,但是实际上是一个“全能类”!
==> 产品是一个多层次的树状结构。而简单工厂模式中只有一个工厂类来对应这些产品。
显然全能类会吃不消。
仔细想想,打印机都继承了共同的抽象类。那么如果工厂也有一个抽象类,是不是就行了?
==> 将工厂类定义成接口,而每新增打印机的类型,就增加该打印机类型对应工厂类的实现。
这样工厂的设计就可以扩展了,而不必去修改原来的代码。
那么现在有:抽象产品,具体产品;抽象工厂,具体工厂。
抽象工厂使用抽象类和接口都可以:
具体的工厂:
而打印机同之前一样,这里不再列出。
测试:
如果再有新的打印机,增加一个新的implements了FactoryPrinter接口的类就好了。
不必修改已有的工厂的代码。符合开闭原则。
这个工厂也叫多态工厂。
缺陷:当产品太多时,工厂也会疯长。这个时候,可以使用抽象工厂模式将一些产品组合起来,使用同一个工厂来生产,而不用为每一种产品都新建一个工厂。
那么打印机这种产品不用变,仿照打印机增加一种新的产品,Ink。
抽象类:
具体油墨:
工厂原来只生产一种产品:打印机。现在生产两种:打印机和其所需要的墨水。
工厂接口:
具体工厂:
然后就可以测试了:
缺陷:当新增加一种打印机和它的油墨的时候,只需要用一个新的工厂
总结:
抽象工厂就是生产一个产品族(Product Family),比如打印机+墨水。
如果产品族退化为一个产品,比如只生产打印机,抽象工厂就退化成了工厂方法模式。
如果工厂方法模式再进行简化,由多个工厂变成只有一个工厂,那就是简单工厂模式。
在简单工厂模式时,可以将工厂生产产品的方法设置为静态的,在测试类中需要生成产品的时候,直接
但是在工厂方法模式和抽象工厂模式中,必须不能设置为静态的。
因为因为工厂方法是抽象方法,要求由子类来动态地实现,而动态性与static所声明的静态性相冲突。
SimpleFactory
FactoryMethod
AbstractFactory
1.DIY
没有工厂的年代,客户需要自己造打印机:public class PrinterLgl { private String name = null; public PrinterLgl(String name) { this.name = name; System.out.println("New: I'm " + this.getClass().getName() + " " + name); } }
public class PrinterLhb { private String name = null; public PrinterLhb(String name) { this.name = name; System.out.println("New: I'm " + this.getClass().getName() + " " + name); } }
客户需要知道怎么去创建一款打印机,客户和打印机就紧密耦合在一起了。
public class TestDIY { public static void main(String[] args) { PrinterLgl plgl1 = new PrinterLgl("puppy"); PrinterLgl plgl2 = new PrinterLgl("guilin"); PrinterLhb plhb1 = new PrinterLhb("haibao"); PrinterLhb plhb2 = new PrinterLhb("haitiao"); } }
为了降低耦合,就出现了工厂类。
2.SimpleFactory
首先,打印机需要有个抽象类:abstract class Printer { protected String name = null; public Printer() { } }
然后,所有的打印机都继承这个类,具体产品:
public class PrinterLgl extends Printer { public PrinterLgl(String name) { this.name = name; System.out.println("New: I'm " + this.getClass().getName() + " " + name); } }
public class PrinterLhb extends Printer { public PrinterLhb(String name) { this.name = name; System.out.println("New: I'm " + this.getClass().getName() + " " + name); } }
再造一个工厂:
public class SimpleFactory { public Printer createPrinter(String brand, String name) { switch (brand) { case "lgl" : return new PrinterLgl(name); case "lhb" : return new PrinterLhb(name); default : System.out.println("New Printer " + name + " fails!"); return null; } } }
接着客户就可以直接提打印机了:
public class TestSimpleFactory { public static void main(String [] args) { SimpleFactory sf = new SimpleFactory(); Printer plgl1 = sf.createPrinter("lgl", "puppy"); Printer plgl2 = sf.createPrinter("lgl", "guilin"); Printer plhb1 = sf.createPrinter("lhb", "haibao"); Printer plhb2 = sf.createPrinter("lhb", "haitiao"); Printer pnull = sf.createPrinter("lll", "liu"); } }
只需要先实例化一个工厂,再用工厂去生产打印机就好了。
这里用到了向上转型,eg:
Printer p = new PrinterLgl(name),进而可以实现多态。
但是简单工厂显然有很多弊端:
最直观的来讲,它违反了开闭原则(对扩展开放,对修改封闭)
即每当需要增加一种打印机的时候,需要修改SimpleFactory类,增加case语句。而根据开闭原则,“修改”是不合适的。
而且每次在创建打印机的时候,还需要传一个brand参数。
3.FactoryMethod
刚刚的简单工厂,在添加新的打印机的时候不需要修改已有的打印机类,但需要修改工厂类。简单工厂模式中的工厂,虽然号称简单工厂,但是实际上是一个“全能类”!
==> 产品是一个多层次的树状结构。而简单工厂模式中只有一个工厂类来对应这些产品。
显然全能类会吃不消。
仔细想想,打印机都继承了共同的抽象类。那么如果工厂也有一个抽象类,是不是就行了?
==> 将工厂类定义成接口,而每新增打印机的类型,就增加该打印机类型对应工厂类的实现。
这样工厂的设计就可以扩展了,而不必去修改原来的代码。
那么现在有:抽象产品,具体产品;抽象工厂,具体工厂。
抽象工厂使用抽象类和接口都可以:
public interface FactoryPrinter { Printer createPrinter(String name); }
具体的工厂:
public class FactoryLgl implements FactoryPrinter { @Override public Printer createPrinter(String name) { return new PrinterLgl(name); } }
public class FactoryLhb implements FactoryPrinter { @Override public Printer createPrinter(String name) { return new PrinterLhb(name); } }
而打印机同之前一样,这里不再列出。
测试:
public class TestFactoryMethod { public static void main(String[] args) { // FactoryLgl flgl = new FactoryLgl(); FactoryPrinter flgl = new FactoryLgl(); Printer plgl1 = flgl.createPrinter("puppy"); Printer plgl2 = flgl.createPrinter("guilin"); // FactoryLhb flhb = new FactoryLhb(); FactoryPrinter flhb = new FactoryLhb(); Printer plhb1 = flhb.createPrinter("haibao"); Printer plhb2 = flhb.createPrinter("haitiao"); } }
如果再有新的打印机,增加一个新的implements了FactoryPrinter接口的类就好了。
不必修改已有的工厂的代码。符合开闭原则。
这个工厂也叫多态工厂。
缺陷:当产品太多时,工厂也会疯长。这个时候,可以使用抽象工厂模式将一些产品组合起来,使用同一个工厂来生产,而不用为每一种产品都新建一个工厂。
4.AbstractFactory
现在假设每一种打印机都需要使用本打印机特有的油墨类型:那么打印机这种产品不用变,仿照打印机增加一种新的产品,Ink。
抽象类:
abstract class Ink { public Ink() { } }
具体油墨:
public class InkA extends Ink { public InkA() { System.out.println("New: I'm " + this.getClass().getName()); } }
public class InkB extends Ink { public InkB() { System.out.println("New: I'm " + this.getClass().getName()); } }
工厂原来只生产一种产品:打印机。现在生产两种:打印机和其所需要的墨水。
工厂接口:
public interface AbstractFactory { Printer createPrinter(String name); Ink createInk(); }
具体工厂:
public class FactoryLgl implements AbstractFactory { @Override public Printer createPrinter(String name) { return new PrinterLgl(name); } @Override public Ink createInk() { return new InkA(); } }
public class FactoryLhb implements AbstractFactory { @Override public Printer createPrinter(String name) { return new PrinterLhb(name); } @Override public Ink createInk() { return new InkB(); } }
然后就可以测试了:
public class TestAbstractFactory { public static void main(String[] args) { // FactoryLgl flgl = new FactoryLgl(); AbstractFactory flgl = new FactoryLgl(); Printer plgl1 = flgl.createPrinter("puppy"); Ink ilgl1 = flgl.createInk(); Printer plgl2 = flgl.createPrinter("guilin"); Ink ilgl2 = flgl.createInk(); // FactoryLhb flhb = new FactoryLhb(); AbstractFactory flhb = new FactoryLhb(); Printer plhb1 = flhb.createPrinter("haibao"); Ink ilhb1 = flhb.createInk(); Printer plhb2 = flhb.createPrinter("haitiao"); Ink ilhb2 = flhb.createInk(); } }
缺陷:当新增加一种打印机和它的油墨的时候,只需要用一个新的工厂
public class FactoryXXX implements AbstractFactory就可以了,无需修改原来工厂的代码,符合开闭原则。但是如果新增加一种产品,比如需要生产打印机+打印机需要的墨水+打印机所需要的纸张,这个时候整个AbstractFactory需要增加一种新的生成纸张的方法,所有的实体工厂也都需要新增这种方法。这可以称为“开闭原则的倾斜性”,不能兼顾所有情况下都满足开闭原则。
总结:
抽象工厂就是生产一个产品族(Product Family),比如打印机+墨水。
如果产品族退化为一个产品,比如只生产打印机,抽象工厂就退化成了工厂方法模式。
如果工厂方法模式再进行简化,由多个工厂变成只有一个工厂,那就是简单工厂模式。
在简单工厂模式时,可以将工厂生产产品的方法设置为静态的,在测试类中需要生成产品的时候,直接
SimpleFactory.createPrinter()就好了。反正就这一个工厂。
但是在工厂方法模式和抽象工厂模式中,必须不能设置为静态的。
因为因为工厂方法是抽象方法,要求由子类来动态地实现,而动态性与static所声明的静态性相冲突。
相关文章推荐
- 简单的数据库连接工厂实现
- Head First设计模式-简单工厂模式
- osg中的工厂模式(c++)
- 工厂布局不合理
- 转:.net设计模式之工厂模式
- C# 工厂模式示例
- 设计模式[2]-旧话重提之工厂模式
- 创建型模式中关于工厂的模式
- 设计模式 - 简单工厂
- spring 框架最基本的功能就是充当创建对象的工厂
- 简单工厂、工厂方法、抽象工厂之小结与区别
- 抽象工厂之“反射”技术
- C#设计模式之简单工厂篇
- javascript学习(11)――[设计模式]工厂模式
- 工厂的烦恼
- 学习PetShop3.0(9)工厂的资料
- 简单的工厂模式+一个抽象接口
- 设计模式之--简单工厂模式
- 设计模式之工厂方法
- Java工厂模式