设计模式的Java 8 Lambda表达式–装饰器设计模式

Decorator模式(也称为Wrapper )允许将行为静态或动态地添加到单个对象,而不会影响同一类中其他对象的行为。 可以将其视为子类的替代方法。 我们知道子类在编译时会增加行为,并且更改会影响原始类的所有实例。 另一方面,装饰可以在运行时为选择性对象提供新的行为。

装饰器与其装饰的组件的接口一致,从而对组件的客户端透明。 装饰器将请求转发到组件,并且可以在转发之前或之后执行其他操作。 透明度允许装饰器递归嵌套,从而允许无限数量的添加职责。 装饰器模式的主要参与者如下所示:

装饰工

  • 组件 –指定可以动态添加职责的对象的接口。
  • ConcreteComponent –定义可以添加其他职责的对象
  • 装饰器 –保留对Component对象的引用并符合Component的接口。 它包含要装饰的Component对象。
  • ConcreteDecorator –向组件添加责任。

现在,让我们来看一个装饰器模式的具体示例,并看一下如何使用lambda表达式对其进行转换。 假设我们有不同类型的书籍,而这些书籍的封面或类别可能不同。 我们可以选择任何书籍,并通过继承来指定类别或语言。 可以将书籍抽象为一类。 之后,任何其他类都可以扩展Book类并覆盖cover或category的方法。 但这不是一种有效的方法。 在这种方法下,子类可能具有从超类扩展过来的不必要的方法。 同样,如果我们必须添加更多的属性或特性,则父类也会有所变化。 更改类的实现应该是最后的选择。

让我们通过使用装饰器模式来采取最佳方法。 我们将使用基本方法为Book创建一个接口:

public interface Book {

    public String describe();

}

BasicBook类可以实现此接口以提供最小的抽象:

public class BasicBook implements Book {

    @Override
    public String describe() {

        return "Book";

    }

}

接下来,让我们定义抽象类BookDecorator ,它将充当Decorator:

abstract class BookDecorator implements Book {

    protected Book book;

    BookDecorator(Book book) {
        this.book = book;
    }

    @Override
    public String describe() {
        return book.describe();
    }
}

BookDecorator类符合Book接口,并且还存储对Book接口的引用。 如果要将类别作为属性添加到Book接口,则可以使用实现BookDecorator接口的具体类。 对于小说类别,我们可以使用以下装饰器:

public class FictionBookDecorator extends BookDecorator {

    FictionBookDecorator(Book book) {
        super(book);
    }

    @Override
    public String describe() {
        return ("Fiction " + super.describe());
    }
}

您可以看到FictionBookDecorator在原始操作(即描述)中添加了图书的类别。 同样,如果要指定“科学”类别,则可以具有相应的“ ScienceBookDecorator”

public class ScienceBookDecorator extends BookDecorator {

    ScienceBookDecorator(Book book) {
        super(book);
    }

    @Override
    public String describe() {
        return ("Science " + super.describe());
    }
}

ScienceBookDecorator还会在原始操作中添加书籍的类别。 也可以有另一套装饰器,指示书籍的封面类型。 我们可以用SoftCoverDecorator来描述这本书有一个软封面。

public class SoftCoverDecorator extends BookDecorator {

	SoftCoverDecorator(Book book) {
		super(book);
	}
	
	@Override
	public String describe() {	
		return (super.describe() + " with Soft Cover");
	}
}

我们还可以使用HardCoverDecorator来描述这本书的精装本。

public class HardCoverDecorator extends BookDecorator {
	
	HardCoverDecorator(Book book) {
		super(book);
	}
	
	@Override
	public String describe() {	
		return (super.describe() + " with Hard Cover");
	}
}

现在,让我们结合定义的所有类和接口,以利用Decorator模式的强大功能。 仅查看所有这些类的一个示例相互作用:

import java.util.List;
import java.util.ArrayList;

public class BookDescriptionMain {
	
	public static void main(String [] args) {
		
		BasicBook book = new BasicBook();
		
		//Specify book as Fiction category
		FictionBookDecorator fictionBook = new FictionBookDecorator(book);
		
		//Specify that the book has a hard cover
		HardCoverDecorator hardCoverBook = new HardCoverDecorator(book);
		
		//What if we want to specify both the category and cover type together
		HardCoverDecorator hardCoverFictionBook = new HardCoverDecorator(fictionBook);				
		
		//Specify book as Science category
		ScienceBookDecorator scienceBook = new ScienceBookDecorator(book);
		
		//What if we want to specify both the category and cover type together
		HardCoverDecorator hardCoverScienceBook = new HardCoverDecorator(scienceBook);				

		//Add all the decorated book items in a list
		List<Book> bookList = new ArrayList<Book>() {
			{
				add(book);
				add(fictionBook);
				add(hardCoverBook);
				add(hardCoverFictionBook);
				add(scienceBook);
				add(hardCoverScienceBook);
			}
		};
		
		//Traverse the list to access all the book items
		for(Book b: bookList) {
			System.out.println(b.describe());
		}		
	}
}

运行此命令可获得以下输出:

Book
Fiction Book
Book with Hard Cover
Fiction Book with Hard Cover
Science Book
Science Book with Hard Cover

它清楚地说明了如何将不同的属性添加到任何预定义的类/对象。 同样,可以组合多个属性。 我试图将所有装饰的书本组合在一个列表中,然后通过遍历该列表来访问它们。

到目前为止,我们所看到的只是标准的装饰器模式,而且已经存在了很长时间。 在这些时候,当函数式编程成为新的流行语时,人们可能会思考Java中对lambda表达式的支持是否会有所不同。 实际上,由于修饰后的接口就像一个函数接口,因此我们可以使用Java中的lambda表达式进行哈希处理。 让我们看一下代码的样子:

import java.util.List;
import java.util.ArrayList;

public class BookDescriptionMainWithLambda {
	
	public static void main(String [] args) {
		
		BasicBook book = new BasicBook();
		
		//Specify book as Fiction category using Lambda expression
		Book fictionBook = () -> "Fiction " + book.describe();
		
		//Specify that the book has a hard cover using Lambda expression
		Book hardCoverBook = () -> book.describe() + " with Hard Cover";
		
		//What if we want to specify both the category and cover type together
		Book hardCoverFictionBook = () -> fictionBook.describe() + " with Hard Cover";				
		
		//Specify book as Science category using Lambda expression
		Book scienceBook = () -> "Science " + book.describe();
		
		//What if we want to specify both the category and cover type together
		Book hardCoverScienceBook = () -> fictionBook.describe() + " with Hard Cover";				

		List<Book> bookList = new ArrayList<Book>() {
			{
				add(book);
				add(fictionBook);
				add(hardCoverBook);
				add(hardCoverFictionBook);
				add(scienceBook);
				add(hardCoverScienceBook);
			}
		};
		
		bookList.forEach(b -> System.out.println(b.describe()));
	}
}

运行此命令可获得类似的输出:

Book
Fiction Book
Book with Hard Cover
Fiction Book with Hard Cover
Science Book
Fiction Book with Hard Cover

我们可以看到,使用lambda表达式会使装饰器的其他类变得多余。 您不需要其他课程; 只需使用lambda表达式指定其他行为。 但是,支持再次找到装饰器以供重新使用。 如果您有具体的装饰器类,则下次也可以重用它。

翻译自: https://www.javacodegeeks.com/2015/12/java-8-lambda-expression-design-patterns-decorator-design-pattern.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值