一、软件设计模式
软件设计模式(Software Design Pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。
也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结 ,具有一定的普遍性,可以反复使用。
软件设计模式的优点:
-
可以提高程序员的思维能力,编程能力和设计能力。 -
使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。 -
使设计的代码可重用性高,可读性强,可靠性好,灵活性好,可维护性强。
二、单例模式
1. 定义
指一个类只有一个实例,且该类能自行创建这个实例的一种模式。
例:
- 一个班级只有一个班主任。
- Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
- 一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
2. 特点
-
单例类只能有一个实例。 -
单例类必须自己创建自己的唯一实例。 -
单例类必须给所有其他对象提供这一实例。
3. 实现方式
单例模式常见的实现方式有:懒汉模式 、饥汉模式 、双重校验锁 、静态内部类 、枚举 ,下面对五种方式进行具体的实现(以Java 为例)。
3.1 懒汉模式
用的时候才去检查有没有实例,如果有则返回,没有则新建.
public class LazyTest {
private static LazyTest instance = null;
private LazyTest(){}
public static synchronized LazyTest getInstance(){
if(instance == null){
instance = new LazyTest();
}
return instance;
}
}
优点:第一次调用才初始化,避免内存浪费。 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
3.2 饿汉模式
饿汉模式相比懒汉模式,在类加载的时候就已经存在一个实例
public class HungryTest {
private static HungryTest instance = new HungryTest();
private HungryTest(){}
public static HungryTest getInstance(){
return instance;
}
}
优点:没有加锁,执行效率会提高。没有线程安全的问题。 缺点:类加载时就初始化,可能产生很多无用的实例,浪费内存。
3.3 双重校验锁
综合了懒汉式和饿汉式两者的优缺点整合而成,采用双锁机制。
代码实现中,特点是在synchronized 关键字内外都加了一层 if 条件判断,这样既保证了线程安全,又比直接上锁提高了执行效率,还节省了内存空间。但是,实现较复杂。
public class DLockTest {
private static DLockTest instance = null;
private DLockTest(){}
public static DLockTest getInstance(){
if(instance == null){
synchronized (DLockTest.class){
if (instance == null){
instance = new DLockTest();
}
}
}
return instance;
}
}
3.4 静态内部类
public class StaticSingleTest {
private static class SingleClass{
private static StaticSingleTest instance = new StaticSingleTest();
}
private StaticSingleTest(){}
public static StaticSingleTest getInstance(){
return SingleClass.instance;
}
}
静态内部类的方式效果类似双检锁,但实现更简单。
对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。
这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
3.5 枚举
public enum EnumTest {
INSTANCE;
public void whateverMethod() {
}
}
这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。
它更简洁,不仅能避免多线程同步问题,还自动支持序列化机制,绝对防止多次实例化。
4. 应用场景
对于 Java 来说,单例模式可以保证在一个 JVM 中只存在单一实例。
单例模式的应用场景主要有以下几个方面:
-
需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 GC。 -
某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。 -
某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。 -
某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。 -
频繁访问数据库或文件的对象。 -
对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。 -
当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。
三、工厂模式
1. 定义
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
简单点来说,工厂模式就是提供一个产生实例化对象的制造厂,每一个工厂都会提供类似的对象(实现共同接口),当我们需要某个类的实例化对象时,我们不需要关心服务端是通过什么方式来获取对象的,我们直接向对应的工厂提出我们的需求即可(实现了客户端和服务端的分离)。
2. 分类
工厂模式有 3 种不同的实现方式,分别是简单工厂模式 、工厂方法模式 和抽象工厂模式 。
2.1 简单工厂模式
我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫**“简单工厂模式”**。
在简单工厂模式中创建实例的方法通常为静态(static)方法
因此简单工厂模式(Simple Factory Pattern)又叫作静态工厂方法模式(Static Factory Method Pattern)。
public class Client {
public interface Product {
void show();
}
static class ConcreteProduct1 implements Product {
public void show() {
System.out.println("具体产品1显示...");
}
}
static class ConcreteProduct2 implements Product {
public void show() {
System.out.println("具体产品2显示...");
}
}
final class Const {
static final int PRODUCT_A = 0;
static final int PRODUCT_B = 1;
static final int PRODUCT_C = 2;
}
static class SimpleFactory {
public static Product makeProduct(int kind) {
switch (kind) {
case Const.PRODUCT_A:
return new ConcreteProduct1();
case Const.PRODUCT_B:
return new ConcreteProduct2();
}
return null;
}
}
}
2.2 工厂方法模式
前面我们说了简单工厂模式违背了开闭原则,而**“工厂方法模式”**是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
public class AbstractFactoryTest {
public static void main(String[] args) {
try {
Product a;
AbstractFactory af;
af = (AbstractFactory) ReadXML.getObject();
a = af.newProduct();
a.show();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
interface Product {
public void show();
}
class ConcreteProduct1 implements Product {
public void show() {
System.out.println("具体产品1显示...");
}
}
class ConcreteProduct2 implements Product {
public void show() {
System.out.println("具体产品2显示...");
}
}
interface AbstractFactory {
public Product newProduct();
}
class ConcreteFactory1 implements AbstractFactory {
public Product newProduct() {
System.out.println("具体工厂1生成-->具体产品1...");
return new ConcreteProduct1();
}
}
class ConcreteFactory2 implements AbstractFactory {
public Product newProduct() {
System.out.println("具体工厂2生成-->具体产品2...");
return new ConcreteProduct2();
}
}
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
public class ReadXML {
public static Object getObject() {
try {
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src/FactoryMethod/config1.xml"));
NodeList nl = doc.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String cName = "FactoryMethod." + classNode.getNodeValue();
Class<?> c = Class.forName(cName);
Object obj = c.newInstance();
return obj;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
2.3 抽象工厂模式
抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构,这里便出现了两个概念:同族和同等级。
使用抽象工厂模式需要满足以下条件:
public class FarmTest {
public static void main(String[] args) {
try {
Farm f;
Animal a;
Plant p;
f = (Farm) ReadXML.getObject();
a = f.newAnimal();
p = f.newPlant();
a.show();
p.show();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
interface Animal {
public void show();
}
class Horse implements Animal {
public Horse() {
System.out.println("具体马类的生成");
}
public void show() {
System.out.println("执行马类的相应操作");
}
}
class Cattle implements Animal {
public Cattle() {
System.out.println("具体牛类的生成");
}
public void show() {
System.out.println("执行马类的相应操作");
}
}
interface Plant {
public void show();
}
class Fruitage implements Plant {
public Fruitage() {
System.out.println("具体水果类生成");
}
public void show() {
System.out.println("执行水果类的相应操作");
}
}
class Vegetables implements Plant {
public Vegetables() {
System.out.println("具体蔬菜类生成");
}
public void show() {
System.out.println("执行蔬菜类的相应操作");
}
}
interface Farm {
public Animal newAnimal();
public Plant newPlant();
}
class SGfarm implements Farm {
public Animal newAnimal() {
System.out.println("新牛出生!");
return new Cattle();
}
public Plant newPlant() {
System.out.println("蔬菜长成!");
return new Vegetables();
}
}
class SRfarm implements Farm {
public Animal newAnimal() {
System.out.println("新马出生!");
return new Horse();
}
public Plant newPlant() {
System.out.println("水果长成!");
return new Fruitage();
}
}
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;
public class ReadXML2 {
public static Object getObject() {
try {
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src/AbstractFactory/config.xml"));
NodeList nl = doc.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String cName = "AbstractFactory." + classNode.getNodeValue();
System.out.println("新类名:" + cName);
Class<?> c = Class.forName(cName);
Object obj = c.newInstance();
return obj;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
抽象工厂模式的扩展有一定的“开闭原则”倾斜性.
四、总结
设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优点。
可以提高程序员的思维能力、编程能力和设计能力。
使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
参考
设计模式-单例模式 设计模式的学习 软件设计模式之单例模式 设计模式系列——抽象工厂模式
|