设计模式详解——单例、工厂、抽象工厂
tags: [#设计模式]
从今天开始,我们逐一看下常用的设计模式,希望能够尽可能搞清楚它们的应用场景,以便我们能够写出更优秀的代码。
1、单例模式
核心要点
- 构造方法私有
- 构造由
static
修饰的、返回实例的方法
优势
- 减少创建
Java
实例所带来的系统开销 - 便于系统跟踪单个Java实例的声明周期、实例状态等
示例代码
package singleton;
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
场景
线程池(threadpool
)、缓存(cache
)、日志对象
2、简单工厂模式
要点
- 通过工厂类的形式进行解耦合
- 依赖关系通过接口解耦合
优缺点
- 让对象的调用者和对象创建过程分离,当对象调用者需要对象时,直接向工厂请求即可;
- 避免了对象的调用者和对象的实现类以硬解码方式耦合,提高了系统的可维护性、拓展性;
- 需要注意的一个陷阱是:当产品修改时,工厂类也要做相应的修改;
示例代码
这里的computer
依赖了Printer
类,但是如果直接写Printer
的话,会直接影响当前类的扩展,比如我们后期增加了Writer
,Writer
和Printer
只是方法不一致,这时候如果用简单工厂模式,就可以完美解决这个问题。
当然,这时依然需要修改OutputFactory
的代码,但是对Computer
是不需要修改的。
public class Computer {
private Output out;
public Computer(Output out) {
this.out = out;
}
public void keyIn(String msg) {
out.getData(msg);
}
public void print() {
out.out();
}
}
简单工厂
package simplefactory;
public class OutputFactory {
public Output getOutput() {
return new Printer();
}
}
接口
package simplefactory;
public interface Output {
final int MAX_CACHE_LINE=200;
void getData(String msg);
void out();
}
接口实现类
package simplefactory;
public class Printer implements Output {
private String[] printData = new String[MAX_CACHE_LINE];
private int dataNum = 0;
@Override
public void getData(String msg) {
if(dataNum >= MAX_CACHE_LINE) {
System.out.println("输出队列已满,添加失败");
} else {
printData[dataNum++] = msg;
}
}
@Override
public void out() {
while(dataNum > 0) {
System.out.println("打印机打印:" + printData[0]);
System.arraycopy(printData, 1, printData, 0, --dataNum);
}
}
}
测试类
package simplefactory;
public class Test {
public static void main(String[] args) {
OutputFactory of = new OutputFactory();
Computer c = new Computer(of.getOutput());
c.keyIn("hello world");
c.keyIn("java");
c.keyIn("spring");
c.print();
}
}
3、工厂方法和抽象工厂
要点
- 和简单工厂相比,工厂方法多了一个接口,也就是工厂接口,
Ouput
子类的工厂类均继承该接口,实现getOutput()
方法 - 当使用工厂方法设计模式时,对象调用者需要与具体的工厂类进行耦合:当需要不同对象时,程序需要调用相应工厂对象的方法来得到所需的对象
- 对于采用工厂方法的设计架构,客户端代码成功与被调用对象实现了分离,但带来了另一种耦合:客户端代码与不同的工厂类耦合
- 为了解决上面的耦合,增加一个工厂类,用于创建不同的工厂对象,这个特殊的工厂类被称为抽象工厂类,这种设计模式被称为抽象工厂模式
比较
和简单工厂相比,抽象工厂降低了目标实例与实例工厂的耦合性,但是它又引入了抽象工厂的耦合关系。
在简单工厂模式中,要创建一个对象的实例,直接调用该对象的工厂方法即可,当然前提条件是增加该对象时要同步增加它的工厂方法;
在抽象工厂模式中,不仅对实例对象做了抽象处理,还对对象的工厂做了抽象处理,所以在实例化一个对象的时候,要先实例化它的工厂,然后再通过工厂方法实例化对象(实线表示代码实际执行流程,虚线表示解耦过程,工厂的工厂创建出来的是抽象工厂的实例,抽象工厂最终创建的是对象的抽象接口)
示例代码
实例工厂接口:
// 工厂接口
package abstractfactory;
import simplefactory.Output;
/**
*
*TODO output工厂接口
*
* @author CaoLei 2018年7月1日下午3:19:36
* OutputFactory
*/
public interface OutputFactory {
Output getOutput();
}
实例工厂实现:
// 工厂方法,工厂类
package abstractfactory;
import simplefactory.BetterPrinter;
import simplefactory.Output;
public class BetterPrinterFactory implements OutputFactory {
@Override
public Output getOutput() {
return new BetterPrinter();
}
}
实例工厂实例化方法:
// 抽象工厂,抽象工厂类
package abstractfactory;
public class OutputFactoryFactory {
public static OutputFactory getOutputFactory(String type) {
if ("better".equals(type)) {
return new BetterPrinterFactory();
} else {
return new PrinterFactory();
}
}
}
好了,今天就先说这三种设计模式,明天我们来继续看其他的设计模式。