设计模式简介
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。
设计模式分类
根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。
创建型模式:这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
结构型模式:这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
行为型模式:这些设计模式特别关注对象之间的通信。
设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3、依赖倒转原则(Dependence Inversion Principle)
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
5、迪米特法则,又称最少知道原则(Demeter Principle)
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。
1.单例设计模式?
1.1什么是单例设计模式单例模式
(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,在类中创建一个单一的私有的对象并私有化构造函数,使得该类不能直接实例化对象。通过提供一种访问其唯一的对象的静态方法来获取该类的对象。
1.2单例模式的几种实现方式
饿汉式:
public class SingletonDemo1 {
private static SingletonDemo1 instance=new SingletonDemo1();
private SingletonDemo1(){}
public static SingletonDemo1 getInstance(){
return instance;
}
}
懒汉式1:
public class SingletonDemo2 {
private static SingletonDemo2 instance=null;
private SingletonDemo2(){
}
public static synchronized SingletonDemo2 getInstance() {
if(instance==null){
instance=new SingletonDemo2();
}
return instance;
}
}
懒汉式2:
private static SingletonDemo3 instance;
private SingletonDemo3(){}
public static SingletonDemo3 getInstance() {
if(instance==null){
synchronized (SingletonDemo3.class){
if(instance==null){
instance=new SingletonDemo3();
}
}
}
return instance;
}
1.3优缺点
优点:
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
- 避免对资源的多重占用(比如写文件操作)。
缺点:
- 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
2.简单工厂模式
2.1什么是工厂模式工厂模式(
Factory Pattern)是 Java 中最常用的设计模式之一。
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象,通过工厂类中的方法来创建相应的对象,通过调用工厂类的方法获取相应的对象,
2.2 简单工厂模式的实现
步骤1:新建一个Anlimal接口
public interface Anlimal {
public void eat();
}
步骤2:创建接口的一个或多个实现类
class Dog implements Anlimal{
@Override
public void eat() {
System.out.println("狗吃");
}
}
class Pig implements Anlimal{
@Override
public void eat() {
System.out.println("猪吃");
}
}
步骤3:创建相应的工厂类
class AnimalFactory {
public Anlimal getEat(String anlimal){
if(anlimal==null){
return null;
}
if(anlimal.equals("pig")){
return new Pig();
}else if(anlimal.equals("dog")){
return new Dog();
}
return null;
}
}
步骤4:测试结果
class AnlimalFactoryDemo{
public static void main(String[] args){
AnimalFactory animalFactory=new AnimalFactory();
//获取Dog对象,并实现其方法
Anlimal anlimal=animalFactory.getEat("pig");
anlimal.eat();
Anlimal anlimal2=animalFactory.getEat("dog");
anlimal2.eat();
}
}
//测试结果
猪吃
狗吃
2.3优缺点
优点:
- 一个调用者想创建一个对象,只要知道其名称就可以了。
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
- 屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:
- 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
3.工厂方法模式
3.1 什么是工厂方法模式
工厂方法模式属于类的创建型模式又被称为多态工厂模式。工厂方法模式的意义在于定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。定义公共接口和一个核心工厂接口,每个公共接口的实现类就有一个对应的核心工厂接口的实现工厂类,通过调用对应的工厂实现类的方法来获取自己的对象。这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
3.2实现案例
步骤1:创建一个公共接口
public interface Car {
void name();
}
步骤2:创建一个核心工厂接口
interface CarFactory {
//工厂方法模式
Car getCar();
}
步骤3:创建一个或多个公共接口的实现类
//Tesla
class Tesla implements Car{
@Override
public void name() {
System.out.println("特斯拉");
}
}
//BaoMa
class BaoMa implements Car{
@Override
public void name() {
System.out.println("宝马");
}
}
步骤4:创建核心工厂类的工厂实现类
class TealaFactory implements CarFactory{
@Override
public Car getCar() {
return new Tesla();
}
}
class BaoMaFactory implements CarFactory{
@Override
public Car getCar() {
return new BaoMa();
}
}
步骤5:测试
class FactoryMethodDemo{
public static void main(String[] args){
Car baoma=new BaoMaFactory().getCar();
Car tesla=new TealaFactory().getCar();
baoma.name();
tesla.name();
}
}
//测试结果
宝马
特斯拉
4.抽象工厂方法
4.1什么是抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
4.2案例实现
实现:
- 将创建 Shape 和 Color 接口和实现这些接口的实体类。 下一步是创建抽象工厂类 AbstractFactory。
- 接着定义工厂类
ShapeFactory 和 ColorFactory,这两个工厂类都是扩展了 AbstractFactory。 - 然后创建一个工厂创造器/生成器类 FactoryProducer。 AbstractFactoryPatternDemo 类使用 FactoryProducer 来获取 AbstractFactory 对象。 它将向 AbstractFactory 传递形状信息
Shape(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。 同时它还向 AbstractFactory 传递颜色信息 Color(RED / GREEN / BLUE),以便获取它所需对象的类型。
步骤1:创建 Shape 和 Color 接口和实现这些接口的实体类。
interface Color
{
void fill();
}
class Red implements Color {
@Override
public void fill() {
System.out.println("Inside Red::fill() method.");
}
}
class Green implements Color {
@Override
public void fill() {
System.out.println("Inside Green::fill() method.");
}
}
class Blue implements Color {
@Override
public void fill() {
System.out.println("Inside Blue::fill() method.");
}
}
interface Shape {
void draw();
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
步骤2:创建抽象工厂类 AbstractFactory。
abstract class AbstractFactory {
//定义获取接口对象的方法
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
步骤3:定义工厂类 ShapeFactory 和 ColorFactory,这两个工厂类都是扩展了 AbstractFactory
class ShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
public Color getColor(String color) {
return null;
}
}
class ColorFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
public Color getColor(String color) {
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
} else if(color.equalsIgnoreCase("GREEN")){
return new Green();
} else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}
步骤4:创建一个工厂创造器/生成器类 FactoryProducer。
class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
步骤5:测试
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
//获取形状工厂
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
//获取形状为 Circle 的对象
Shape shape1 = shapeFactory.getShape("CIRCLE");
//调用 Circle 的 draw 方法
shape1.draw();
//获取形状为 Rectangle 的对象
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取形状为 Square 的对象
Shape shape3 = shapeFactory.getShape("SQUARE");
//调用 Square 的 draw 方法
shape3.draw();
//获取颜色工厂
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
//获取颜色为 Red 的对象
Color color1 = colorFactory.getColor("RED");
//调用 Red 的 fill 方法
color1.fill();
//获取颜色为 Green 的对象
Color color2 = colorFactory.getColor("Green");
//调用 Green 的 fill 方法
color2.fill();
//获取颜色为 Blue 的对象
Color color3 = colorFactory.getColor("BLUE");
//调用 Blue 的 fill 方法
color3.fill();
}
}
//测试结果
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.
4.3优缺点
优点:
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
- 产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
5.代理模式
5.1什么是代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
5.2 实现案例
实现:
- 我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。 ProxyPatternDemo 类使用 ProxyImage 来获取要加载的 Image对象,并按照需求进行显示。
步骤1:创建一个 Image 接口和实现了 Image 接口的实体类。
public interface Image {
void display();
}
public class RealImage implements Image {
private String fileName;
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
public RealImage(String fileName){
this.fileName=fileName;
loadFromDisk(fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " + fileName);
}
}
步骤2:创建一个代理类ProxyImage
public class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
步骤3:测试
public class ProxyPattenDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}
//测试结果
Loading test_10mb.jpg
Displaying test_10mb.jpg
Displaying test_10mb.jpg
5.3 优缺点
优点:
- 1、职责清晰。 2、高扩展性。 3、智能化。
缺点:
- 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
6.原型模式
6.1什么是原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
6.2 实现案例
步骤1:创建一个实现了 Cloneable 接口的抽象类。
public abstract class Shape implements Cloneable {
private String id;
protected String type;
abstract void draw();
public String getType(){
return type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
步骤2:继承 Shape 类的实体类
class Rectangle extends Shape {
public Rectangle(){
type = "Rectangle";
}
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
class Square extends Shape {
public Square(){
type = "Square";
}
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
class Circle extends Shape {
public Circle(){
type = "Circle";
}
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
步骤3:创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。
public class ShapeCache {
private static Hashtable<String, Shape> shapeMap
= new Hashtable<String, Shape>();
public static Shape getShape(String shapeId) {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}
// 对每种形状都运行数据库查询,并创建该形状
// shapeMap.put(shapeKey, shape);
// 例如,我们要添加三种形状
public static void loadCache() {
Circle circle = new Circle();
circle.setId("1");
shapeMap.put(circle.getId(),circle);
Square square = new Square();
square.setId("2");
shapeMap.put(square.getId(),square);
Rectangle rectangle = new Rectangle();
rectangle.setId("3");
shapeMap.put(rectangle.getId(),rectangle);
}
}
步骤4:测试
public class PrototypePatternDemo {
public static void main(String[] args) {
ShapeCache.loadCache();
Shape clonedShape = (Shape) ShapeCache.getShape("1");
System.out.println("Shape : " + clonedShape.getType());
Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
System.out.println("Shape : " + clonedShape2.getType());
Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
System.out.println("Shape : " + clonedShape3.getType());
}
}
//运行结果
Shape : Circle
Shape : Square
Shape : Rectangle
6.3优缺点
优点:
- 1、性能提高。 2、逃避构造函数的约束。
缺点:
- 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
2、必须实现 Cloneable 接口。
7.外观模式
7.1什么是外观模式
外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。
这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
7.2实现案例
实现:
- 我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。下一步是定义一个外观类 ShapeMaker。 ShapeMaker
类使用实体类来代表用户对这些类的调用。FacadePatternDemo 类使用 ShapeMaker 类来显示结果。
步骤1:定义接口和实现类
public interface Shape {
void draw();
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Square::draw()");
}
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
步骤2:创建一个外观类
public class ShapeMaker {
private Shape circle;
private Shape square;
public ShapeMaker(){
circle=new Circle();
square=new Square() ;
}
public void drawCircle() {
circle.draw();
}
public void drawSquare() {
square.draw();
}
}
步骤3:测试
public class FacadePatternDemo {
public static void main(String[] args){
ShapeMaker shapeMaker=new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawSquare();
}
}
//测试结果
Circle::draw()
Square::draw()
8.装饰器模式
8.1什么是装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。
8.2实现案例
实现:
- 我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类
ShapeDecorator,并把 Shape 对象作为它的实例变量。
RedShapeDecorator 是实现了 ShapeDecorator 的实体类。
DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。
步骤1:创建接口和实现类
public interface Shape {
void draw();
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
步骤2:创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。
public abstract class ShapeDecorator implements Shape {
protected Shape shapeDocorator;
public ShapeDecorator(Shape shapeDocorator ){
this.shapeDocorator=shapeDocorator;
}
@Override
public void draw() {
shapeDocorator.draw();
}
}
步骤3:创建RedShapeDecorator 是实现了 ShapeDecorator 的实体类。
public class RedShapeDecorator extends ShapeDecorator {
public Shape decoratedShape;
//如果抽象父类有构造函数必须写构造构造函数,并手动调用父类构造函数,
public RedShapeDecorator(Shape shapeDocorator) {
super(shapeDocorator);
//把 Shape 对象作为它的实例变量。
this.decoratedShape=shapeDocorator;
}
//复写装饰类方法,并在此方法中调用扩展的功能
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
//编写扩展功能方法
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
步骤4:测试
public class DecoratorPatternDemo {
public static void main(String[] args){
Shape circle=new Circle();
ShapeDecorator redCircle=new RedShapeDecorator(new Circle());
ShapeDecorator redRectangle=new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();
System.out.println("\nCircle of red border");
redCircle.draw();
System.out.println("\nRectangle of red border");
redRectangle.draw();
}
}
//运行结果
Circle with normal border
Shape: Circle
Circle of red border
Shape: Circle
Border Color: Red
Rectangle of red border
Shape: Rectangle
Border Color: Red
8.3 优缺点
优点:
- 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:
- 多层装饰比较复杂。
9.责任链模式
9.1什么是责任链模式
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
9.2 案例实现
实现:我们创建抽象类 AbstractLogger,带有详细的日志记录级别。然后我们创建三种类型的记录器,都扩展了 AbstractLogger。每个记录器消息的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个记录器。
步骤1:创建抽象的记录器类。
public abstract class AbstractLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
//责任链中的下一个元素
protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger){
this.nextLogger = nextLogger;
}
public void logMessage(int level, String message){
if(this.level <= level){
write(message);
}
if(nextLogger !=null){
nextLogger.logMessage(level, message);
}
}
abstract protected void write(String message);
}
步骤2:创建扩展了该记录器类的实体类
public class FileLogger extends AbstractLogger {
public FileLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("File::Logger: " + message);
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Error Console::Logger: " + message);
}
}
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Standard Console::Logger: " + message);
}
}
步骤3:测试。创建不同类型的记录器。赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。每个记录器中的下一个记录器代表的是链的一部分。
public class ChainPatternDemo {
//把对象封装成一个链,返回最高等级的对象
private static AbstractLogger getChainOfLoggers(){
AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
errorLogger.setNextLogger(fileLogger);
fileLogger.setNextLogger(consoleLogger);
return errorLogger;
}
public static void main(String[] args) {
AbstractLogger loggerChain = getChainOfLoggers();
loggerChain.logMessage(AbstractLogger.INFO, "This is an information.");
loggerChain.logMessage(AbstractLogger.DEBUG,
"This is a debug level information.");
loggerChain.logMessage(AbstractLogger.ERROR,
"This is an error information.");
}
}
//运行结果
Standard Console::Logger: This is an information.
File::Logger: This is a debug level information.
Standard Console::Logger: This is a debug level information.
Error Console::Logger: This is an error information.
File::Logger: This is an error information.
Standard Console::Logger: This is an error information.
9.3 优缺点
优点:
- 降低耦合度。它将请求的发送者和接收者解耦。
- 简化了对象。使得对象不需要知道链的结构。
- 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
- 增加新的请求处理类很方便。
缺点:
- 不能保证请求一定被接收。
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
- 可能不容易观察运行时的特征,有碍于除错。