本文参考:
常见设计模式解析,应用场景以及优点(一)单例,工厂,抽象工厂,构造者_口怪物口的博客-CSDN博客_简述常见的工厂模式以及单例模式的使用场景
工厂模式
工厂模式(Factory Pattern) 是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
简单工厂模式
简单工厂模式只是将不同对象的创建操作进行了一层简单的封装,其实也就是把不同对象的创建操作全都单独放到一个类中,这个类就成为了简单工厂类。
- 实现一个电脑工厂,由电脑工厂根据需求生成不同品牌的电脑。
-
创建一个电脑抽象类
public abstract class Computer { public abstract void use(); }
-
创建抽象类的具体实现类,两款电脑
public class AppleComputer extends Computer{ public AppleComputer(){ System.out.println("生产了Apple电脑..."); } @Override public void use() { System.out.println("使用了Apple电脑..."); } }
public class LenoveComputer extends Computer{ public LenoveComputer(){ System.out.println("生产了Lenove电脑..."); } @Override public void use() { System.out.println("使用了Lenove电脑..."); } }
-
创建一个电脑工厂
public class SimpleComputerFactory { public static Computer produceComputer(String brand){ if(brand==null){ return null; } if(brand.equalsIgnoreCase("Apple")){ return new AppleComputer(); }else if(brand.equalsIgnoreCase("Lenove")){ return new LenoveComputer(); } return null; } }
-
测试
public class SimpleFactoryTest { public static void main(String[] args) { SimpleComputerFactory computerFactory = new SimpleComputerFactory(); Computer lenove = computerFactory.produceComputer("Lenove"); lenove.use(); Computer apple = computerFactory.produceComputer("Apple"); apple.use(); } }
优点:简单工厂模式可以根据需求,动态生成使用者所需类的对象,而使用者不用去知道怎么创建对象,使得各个模块各司其职,降低了系统的耦合性。
缺点:拓展性差,违背了开闭原则,由于只有一个工厂类,新增产品时,需要修改这个工厂类。
应用场景:调用方不用担心具体实例化,只需要关心有没有自己想要获取的类,工厂内部通过字符串进行判断返回,将创建实例和使用实例的工作分开。
工厂方法模式
简单工厂模式只有一个总工厂,工厂方法模式额外定义了一个抽象总工厂,在总工厂类下还有许多子工厂,不同的对象由其对应的子工厂进行创建。与简单工厂模式对比起来,一个商品需要创建一个额外的工厂类,这样子当我们需要扩展一个新产品时,只需要拓展一个工厂类就行,不用修改总工厂的代码,满足了开闭原则。
- 实现一个电脑工厂,再根据不同品牌实现电脑工厂子类,由电脑工厂子类根据需求生成不同品牌的同一类型的电脑。
-
创建一个电脑抽象类
public abstract class Computer { public abstract void use(); }
-
创建抽象类的具体实现类,两款电脑
public class AppleComputer extends Computer{ public AppleComputer(){ System.out.println("生产了Apple电脑..."); } @Override public void use() { System.out.println("使用了Apple电脑..."); } }
public class LenoveComputer extends Computer{ public LenoveComputer(){ System.out.println("生产了Lenove电脑..."); } @Override public void use() { System.out.println("使用了Lenove电脑..."); } }
-
创建一个抽象电脑总工厂,里面有一个produce()生产的抽象方法
public abstract class MethodFactory { public abstract Computer produce(); }
-
创建产品各自的分工厂
public class AppleComputerFactory extends MethodFactory{ @Override public Computer produce() { return new AppleComputer(); } }
public class LenoveComputerFactory extends MethodFactory{ @Override public Computer produce() { return new LenoveComputer(); } }
-
测试
public class MethodFactoryTest {
public static void main(String[] args) {
MethodFactory appleComputerFactory = new AppleComputerFactory();
Computer appleComputer = appleComputerFactory.produce();
appleComputer.use();
MethodFactory lenoveComputerFactory = new LenoveComputerFactory();
Computer lenoveComputer = lenoveComputerFactory.produce();
lenoveComputer.use();
}
}
优点:扩展性好,符合了开闭原则,新增一种产品时,只需增加改对应的产品类和对应的工厂子类即可。比如样例实现中,当我们需要一个苹果电脑时,只需要去新增一个苹果电脑类和一个苹果工厂类即可,而无需去修改原有的代码。符合单一职责原则,每个工厂只负责一种产品,而不是由一个工厂去生成所有商品。
缺点: 当我们新增产品时,还需要提供对应的工厂类,系统中类的个数将会成倍增加,相当于增加了系统的复杂性。
使用场景:将创建实例和使用实例的工作分开,低耦合性地创建类,同时符合开闭原则。
抽象工厂模式
抽象工厂模式有点像是工厂方法模式的升级版。
工厂方法模式生产的是同一品牌的一种类型的商品,而抽象工厂模式可以生产同一品牌不同类型的商品。相当于是抽象电脑总工厂里面的抽象方法变多了,同一子工厂生产的类型也多了。
实现一个电脑工厂,再根据不同品牌实现电脑工厂子类,由电脑工厂子类根据需求生成不同品牌的不同类型的电脑。
-
创建不同类型的电脑抽象类
public abstract class DesktopComputer { public abstract void use(); }
public abstract class NotebookComputer { public abstract void use(); }
-
创建抽象类的具体实现类,两种品牌的电脑,每种电脑各有两种类型
public class AppleDesktopComputer extends DesktopComputer{ public AppleDesktopComputer(){ System.out.println("生产了Apple的台式电脑..."); } @Override public void use() { System.out.println("使用了Apple的台式电脑..."); } }
public class AppleNotebookComputer extends NotebookComputer{ public AppleNotebookComputer(){ System.out.println("生产了Apple的笔记本电脑..."); } public void use() { System.out.println("使用了Apple的笔记本电脑..."); } }
public class LenoveDesktopComputer extends DesktopComputer{ public LenoveDesktopComputer(){ System.out.println("生产了Lenove的台式电脑..."); } @Override public void use() { System.out.println("使用了Lenove的台式电脑..."); } }
public class LenoveNotebookComputer extends NotebookComputer{ public LenoveNotebookComputer(){ System.out.println("生产了Lenove的笔记本电脑..."); } public void use() { System.out.println("使用了Lenove的笔记本电脑..."); } }
-
创建生产不同类型电脑的总工厂抽象类
public class AppleFactory extends AbstractFactory{ public DesktopComputer produceDesktopComputer() { return new AppleDesktopComputer(); } public NotebookComputer produceNotebookComputer() { return new AppleNotebookComputer(); } }
public class LenoveFactory extends AbstractFactory{ public DesktopComputer produceDesktopComputer() { return new LenoveDesktopComputer(); } public NotebookComputer produceNotebookComputer() { return new LenoveNotebookComputer(); } }
-
测试
public class AbstractFactoryTest { public static void main(String[] args) { AppleFactory appleFactory = new AppleFactory(); DesktopComputer appleDesktopComputer = appleFactory.produceDesktopComputer(); appleDesktopComputer.use(); NotebookComputer appleNotebookComputer = appleFactory.produceNotebookComputer(); appleNotebookComputer.use(); LenoveFactory lenoveFactory = new LenoveFactory(); DesktopComputer lenoveDesktopComputer = lenoveFactory.produceDesktopComputer(); lenoveDesktopComputer.use(); NotebookComputer lenoveNotebookComputer = lenoveFactory.produceNotebookComputer(); lenoveNotebookComputer.use(); } }
优点:工厂总抽象类可以创建多个类型的产品,当有需求时,可以创建相关产品子类和子工厂类来获取。也就是可以满足生产不同品牌的不同类型的电脑。
缺点: 扩展新种类产品时困难。抽象工厂模式需要我们在工厂抽象类中提前确定了可能需要的产品种类,以满足不同品牌的多种产品的需求。但是如果我们需要的产品种类并没有在工厂抽象类中提前确定,那我们就需要去修改工厂抽象类了,而一旦修改了工厂抽象类,那么所有的工厂子类也需要修改,这样显然扩展不方便。
使用场景:适用于提供的某实例或某些相关联的实例种类较多的情况,或者是该实例创建方式灵活扩展的可能性较大的情况.将创建实例和使用实例的工作分开,如JUC中线程池创建新线程的方式是多样话的并且是可扩展的,就是用ThreadFactory可扩展接口来实现