工厂模式是分为三种,分别是简单工厂,工厂方法,抽象工厂。其中工厂方法和抽象工厂是GoF23种设计模式中的一种,而简单工厂则不是一种设计模式,更加可以理解的是一种编码时候预定俗称的一种习惯。那么,就在接下来三点中分别去分析理解工厂模式。
一 简单工厂:通过实例化一个工厂类,来获取对应的产品实例。我们不需要关注产品本身如何被创建的细节,只需要通过相应的工厂就可以获得相应的实例。简单工厂包括三种角色:
1.工厂:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
2.抽象产品 :简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
3.具体产品:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
比如以下例子:
(类设计的UML图)
1.Drinks作为产品的抽象类并且有抽象方法produce();(抽象产品)public abstract class Drinks { protected abstract void produce();}2.Sprite继承Drinks是要被具体生产出来的产品,他重写了produce()方法。(具体产品)public class Sprite extends Drinks { @Override protected void produce() { System.out.println("drink sprite"); }} 3.Cola同样也继承了Drinks,是要被生产出来的具体产品。(具体产品)public class Cola extends Drinks { @Override protected void produce() { System.out.println("Drink Cola"); }} 4.DrinksFactory为简单工厂,向外暴露produceDrink方法来获取产品的实例(工厂)public class DrinksFactory { public Drinks produceDrink(Class className){ try { return (Drinks) Class.forName(className.getName()).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; }} 5.Client为应用层,Client端想要获取到Cola或者Sprite对象,只要通过DrinkFactory中的produceDrink方法传入相对应的对应的产品public class Client { public static void main(String[] args) { DrinksFactory factory = new DrinksFactory(); Cola cola = (Cola) factory.produceDrink(Cola.class); cola.produce(); }}
简单工厂的优点:1.不需要关心类的创建细节。2.减轻类之间的耦合依赖,具体类的实现只是依赖于简单工厂,而不依赖其他类。 简单工厂的缺点:1.扩展复杂,当简单工厂需要生产出另外一种产品的时候,需要扩展工厂的内部创建逻辑,比较有可能引起较大的故障2.由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中
二.工厂方法
工厂方法的定义是:定义一个创建对象的接口,让实现这个接口的的类去决定实例化具体的类。工厂方法让类的实例化推迟到实现接口的子类中进行。
比如说,我现在需要一瓶可乐,有可口可乐公司生产的可乐也有百事可乐公司生产的可乐,那么对于可乐这个产品等级(抽象工厂中会具体说明),具体生产什么可乐并不是在一个工厂实现,而是由一个可乐工厂指定一个标准(接口里面的抽象方法),可口可乐公司百事可乐公司只要按照这个标准去生产就可以了。
(2)工厂方法的Uml类图
1.Cola此类是产品的父类public abstract class Cola { protected abstract void drinks();}2.PepsiCola继承Cola,是要生产的产品之一public class PepsiCola extends Cola { @Override protected void drinks() { System.out.println("Drinks PepsiCola"); }}3.CoCoCola同样继承Cola,也是要生产的产品之一public class CoCoCola extends Cola { @Override protected void drinks() { System.out.println("Drinks cococoLa"); }}4.ColaFacotry定义抽象工厂,指定要生产此类产品的规范(存在的方法与属性),指定工厂方法public interface ColaFacotry { Cola produce(Class<Cola> cola);}5.PepsiColaFactory定义子类工厂,它继承抽象工厂,实现了对某一产品等级的产品的获得public class PepsiColaFactory implements ColaFacotry { public PepsiCola produce(Class cola) { if (cola.isInstance(PepsiCola.class)){ return new PepsiCola(); } return null; }}6.ColaFacotry,是规定工厂方法去获得拿一些的产品等级的商品,比如说,我规定生产的产品等级是可乐和草莓可乐,那么对于它的实现类来说,也就是其子类中的重载方法来说去具体实现获取产品的具体实现。public interface ColaFacotry { Cola produce(Class<Cola> cola);}
三.抽象工厂
抽象工厂是提供了创建一系列服务的的对象的接口。那么问题就来了,怎么区分和工厂方法中的服务对象宁?此时就需要对一组概念有所理解,即产品等级和产品族,我从网上找到下面这张图,进行解释说明。在图(4)中,我们可以通过横向和纵向的比较,横向是某一个手机厂商如苹果,小米等,他们不仅仅生产手机,还生产电脑,耳机等一系类产品,那么我们把苹果,小米,华为这样的厂商可以认为他们生产的是一个产品族,而他们自己本身就是一个抽象工厂的具体实现;那么纵向来看,不管是小米华为还是苹果,他们生产的产品是按照一定的规则来生产,显示屏,电池,处理器等等,所以对于纵向的产品来说,他们又是属于同一个产品等级,我们亦可以称他们的实现为工厂方法。
综上所述,抽象工厂解决的是横向的产品族,工厂方法解决的是纵向的产品等级。具体抽象工厂请看代码。
(3)产品等级和产品族(图片来自https://laravel-china.org/topics/18598?order_by=created_at&)
(4)产品等级示意图
1.AbstractFactory 抽象工厂
public interface AbstractFactory { public Phone producePhone(); public Computer producaComputer();}2.AppleFactory具体工厂的实现一public class AppleFactory implements AbstractFactory { public Phone producePhone() { return new Iphone(); } public Computer producaComputer() { return new Mac(); }}3.MiFactory具体工厂的实现二public class MiFactory implements AbstractFactory { public Phone producePhone() { return new MiPhone(); } public Computer producaComputer() { return new MiComputer(); }}4.Phone抽象产品等级一public abstract class Phone { public abstract void call();}5.Iphone具体产品一public class Iphone extends Phone { @Override public void call() { System.out.println("Iphone call"); }}6.MiPhone具体产品一public class MiPhone extends Phone { @Override public void call() { System.out.println("Mi Phone call"); }}7.Computer抽象产品等级二public abstract class Computer { public abstract void work();}8.Mac具体产品一public class Mac extends Computer { @Override public void work() { System.out.println("MAC work"); }}9.MiComputer 具体产品二public class MiComputer extends Computer { @Override public void work() { System.out.println("MI computer word"); }}10.客户端public class Clint { public static void main(String[] args) { AppleFactory appleFactory = new AppleFactory(); appleFactory.producaComputer().work(); appleFactory.producePhone().call(); MiFactory miFactory = new MiFactory(); miFactory.producaComputer().work(); miFactory.producePhone().call(); }}
(5)抽象工厂UML类图
从UML类图中不难看出,我们如果需要拓展抽象工厂里面的方法会比较麻烦,因为我们必须修改抽象类以及添加对应的产品等级,这样修改量比较大,但是每种产品之间相互解耦,符合程序设计的“高内聚低耦合”的思想。
最后,不管是抽象工厂还是工厂方法甚至是简单工厂,他们的存在都有一定的优缺点,在设计程序的时候要根据具体情况进行取舍,不存在那种设计好那种设计特别差,只是针对不同的业务场景的不一样的处理。
原文地址:https://www.cnblogs.com/gclokok/p/10029088.html