跳转到内容

空对象模式

维基百科,自由的百科全书

在面向对象编程中,空对象(英語:null object),是不具有被引用的值或具有已定义的中性(null)行为的对象。空对象设计模式,描述了这种对象的用法和它们的行为,它最初被描述为“空值”(Void值)[1] ,后来在程序设计的模式语言(英语:Pattern Languages of Programs#Publications)丛书中被描述为“空对象”[2]。

示例

[编辑]

C++

[编辑]

作为具有到对象的静态类型引用的语言,C++诠释了为何空对象成为了一种复杂模式:

import std;

using std::unique_ptr;

class Animal {
public:
    virtual ~Animal() = default;

    virtual void makeSound() const = 0;
};

class Dog: public Animal {
public:
    virtual void makeSound() const override { 
        std::println("Woof!"); 
    }
};

class NullAnimal: public Animal {
public:
    virtual void makeSound() const override {
        // silence...
    }
};

int main() {
    unique_ptr<Animal> dog = std::make_unique<Dog>();
    dog->makeSound(); // outputs "Woof!"

    unique_ptr<Animal> unknown = std::make_unique<NullAnimal>();
    unknown->makeSound(); // outputs nothing, but does not throw a runtime exception
}

这里的想法是有一些需要到一个Animal对象的指针或引用的场合,但却不能得到适合的对象。在遵循标准的C++中空引用是不可能的。空Animal*指针是可能的,它可以被用为占位符,但不能用于直接分派:a->makeSound()在a是空指针的情况下有着未定义的行为。

空对象模式通过提供特殊的NullAnimal类来解决这个问题,这个类可以被实例化而绑定到有一个Animal指针或引用。必须为每个有空对象的类层级创建一个特殊的空类。在C++中,函数或方法可以显式的声明其参数是否允许为空:

// Function which requires an Animal instance, and will not accept null.
void doSomething(const Animal& animal) {
    // animal may never be null here.
}

// Function which may accept an Animal instance or null.
void doSomething(const Animal* animal) {
    // animal may be null.
}

Java

[编辑]

下面是Java的例子:

package org.wikipedia.examples;

interface Animal {
	void makeSound();
}

class Dog implements Animal {
	public void makeSound() {
		System.out.println("Woof!");
	}
}

class NullAnimal implements Animal {
	public void makeSound() {
        // silence...
	}
}

public class Example {
    public static void main(String[] args) {
        Animal dog = new Dog();
        dog.makeSound(); // outputs "Woof!"

        Animal unknown = new NullAnimal();
        unknown.makeSound(); // outputs nothing, but does not throw a runtime exception
    }
}

C#

[编辑]

C#是可以真正实现空对象模式的语言。这个例子展示了会叫唤的动物对象,并将C#的null关键字替代为NullAnimal的一个实例Null:

namespace Wikipedia.Examples;

// Null object pattern implementation:
using System;

// Animal interface is the key to compatibility for Animal implementations below.
interface IAnimal {
	void MakeSound();
}

// Animal is the base case.
abstract class Animal : IAnimal {
	// A shared instance that can be used for comparisons
	public static readonly IAnimal Null = new NullAnimal();
	
	// The Null Case: this NullAnimal class should be used in place of C# null keyword.
	private class NullAnimal : Animal {
		public override void MakeSound() {
			// Purposefully provides no behaviour.
		}
	}
	public abstract void MakeSound();
}

// Dog is a real animal.
class Dog : Animal {
	public override void MakeSound() {
		Console.WriteLine("Woof!");
	}
}

/*
 * Simplistic usage example in a Main entry point.
 */
static class Program {
	static void Main() {
		IAnimal dog = new Dog();
		dog.MakeSound(); // outputs "Woof!"

		/* Instead of using C# null, use the Animal.Null instance.
         * This example is simplistic but conveys the idea that if the Animal.Null instance is used then the program
         * will never experience a .NET System.NullReferenceException at runtime, unlike if C# null were used.
         */
		IAnimal unknown = Animal.Null;  //<< replaces: IAnimal unknown = null;
		unknown.MakeSound(); // outputs nothing, but does not throw a runtime exception        
	}
}

参见

[编辑]

引用

[编辑]
  1. ^ Kühne, Thomas. Proceedings of the First International Conference on Object-Oriented Technology, White Object-Oriented Nights 1996 (WOON'96), St. Petersburg, Russia. 1996. 
  2. ^ Woolf, Bobby. Null Object. Martin, Robert; Riehle, Dirk; Buschmann, Frank (编). Pattern Languages of Program Design 3. Addison-Wesley. 1998. 

外部链接

[编辑]