面向复用的设计模式
结构型模式 Structural patterns
适配器模式 Adapter
用途:将某个类/接口转换为client期望的其他形式 例:客户端想要调用LegacyRectangle的display方法,但是接口不匹配,后两个参数客户端提供的是x2, y2,而不是w和h。
- class LegacyRectangle {
- void display(int x1, int y1, int w, int h) {... }
- }
- class Client {
- public display() {
- new LegacyRectangle().display(x1, y1, x2, y2);
- }
- }
arduino
可以新增适配器类解决这个问题,客户端调用这个适配器类的方法即可。
- interface Shape {
- void display(int x1, int y1, int x2, int y2);
- }
将其实现,方法中将x2, y2转换成了w, h
- class Rectangle implements Shape {
- void display(int x1, int y1, int x2, int y2) {
- new LegacyRectangle().display(x1, y1, x2-x1, y2-y1);
- }
- }
java
这是原本要调用的类
- class LegacyRectangle {
- void display(int x1, int y1, int w, int h) {...}
- }
客户端中,调用适配器类的方法即可适配接口
- class Client {
- Shape shape = new Rectangle();
- public display() {
- shape.display(x1, y1, x2, y2);
- }
- }
routeros
装饰器模式 Decorator
当类需要有不同特性的实现,又需要将这些特性组合起来使用时,可以使用装饰器模式实现
- 为对象增加不同侧面的特性
- 对每一个特性构造子类,通过委派机制增加到对 象上
缺点:
- 不满足LSP
- 若需要实现不同特性的任意组合,父类接口中需包含所有子类的方法
例:先实现一个最基础的堆
- interface Stack {
- void push(Item e);
- Item pop();
- }
- public class ArrayStack implements Stack {
- ... //rep
- public ArrayStack() {...}
- public void push(Item e) {
- ...
- }
- public Item pop() {
- ...
- }
- ...
- }
java
然后新建一个用于装饰的基础类,基础的两个方法通过委托实现。
- public abstract class StackDecorator implements Stack {
- protected final Stack stack;
- public StackDecorator(Stack stack) {
- this.stack = stack;
- }
- public void push(Item e) {
- stack.push(e);
- }
- public Item pop() {
- return stack.pop();
- }
- ...
- }
cpp
若要实现堆的撤销功能,则新建一个类,继承装饰器,实现Stack,并在其中添加新的undo方法。同样,基础的push, pop操作通过委托实现,不过要在push前将其记录下来。
- public class UndoStack
- extends StackDecorator
- implements Stack {
- private final UndoLog log = new UndoLog();
- public UndoStack(Stack stack) {
- super(stack);
- }
- public void push(Item e) {
- log.append(UndoLog.PUSH, e);
- super.push(e);
- }
- public void undo() {
- //implement decorator behaviors on stack
- }
- ...
- }
java
其他类型的修饰同理。
在使用时,将不同类型的特性一层一层套在一起
- Stack t = new SecureStack(
- new SynchronizedStack(
- new UndoStack(s))
$\color{red}{注:使用这种方法需要在Stack接口中包含Undo, Secure, Synchronized中的所有方法,否则无法调用特性方法,也无法类型转换再调用}$
外观模式 Facade
Facade模式提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用 例如在lab3中,要判断资源/位置是否冲突以及寻找前序项。若这些功能都由客户端实现的话,则会造成大量方法的调用,不美观也不好修改。可以通过facade模式,新建一个类来将这些操作封装在一起,统一接受客户端的请求执行操作。
行为类模式 Behavioral patterns
策略模式 Strategy
若有多种不同的算法实现同一个任务,则可以使用strategy模式使客户端动态切换算法。 为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例
例:购物时的付款方式,可以选则多种付款方式
- public interface PaymentStrategy {
- public void pay(int amount);
- }
可以选择信用卡付款
- public class CreditCardStrategy implements PaymentStrategy {
- private String name;
- private String cardNumber;
- private String cvv;
- private String dateOfExpiry;
- public CreditCardStrategy(String nm, String ccNum,
- String cvv, String expiryDate){
- this.name=nm;
- this.cardNumber=ccNum;
- this.cvv=cvv;
- this.dateOfExpiry=expiryDate;
- }
- @Override
- public void pay(int amount) {
- System.out.println(amount +" paid with credit card");
- }
- }
arduino
也可以选择Paypal付款
- public class PaypalStrategy implements PaymentStrategy {
- private String emailId;
- private String password;
- public PaypalStrategy(String email, String pwd){
- this.emailId=email;
- this.password=pwd;
- }
- @Override
- public void pay(int amount) {
- System.out.println(amount + " paid using Paypal.");
- }
- }
arduino
在购物车结账时,我们就可以选择二者之一了。
例如传入的参数是PaypalStrategy类的,使用的就是Paypal付款。
- public class ShoppingCart {
- ...
- public void pay(PaymentStrategy paymentMethod){
- int amount = calculateTotal();
- paymentMethod.pay(amount);
- }
- }
angelscript
模板模式 Template Method
- 做事情的步骤一样,但具体方法不同
- 共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现
- 使用继承和重写实现模板模式
例:每天早上都要起床,晚上都要睡觉,中午都要恰饭,而每天的工作内容不同。
设计一天的模板如下
- public abstract class OneDay{
- public LocalDate date;
- public final void getUp(){
- System.out.println("Get Up.");
- }
- public final void eat(){
- System.out.println("要恰饭的嘛。");
- }
- public abstract void work();
- public final void sleep(){
- System.out.println("Sleep.");
- }
- }
arduino
在不同子类中重写work方法:
- public class Study extends OneDay{
- @Override
- public void work(){
- System.out.println("Study.");
- }
- }
scala
- public class TouchFish extends OneDay{
- @Override
- public void work(){
- System.out.println("摸了。");
- }
- }
scala
即可在模板上添加不同的工作内容。
迭代器模式 Iterator
客户端希望遍历被放入容器/集合类的一组ADT对象,无需关心容器的具体类型
也就是说,不管对象被放进哪里,都应该提供同样的遍历方式
需要实现Iterable接口与其中的iterator方法。
- public interface Iterable<T> {
- ...
- Iterator<T> iterator();
- }
routeros
并在类中内嵌一个类实现Iterator类,在其中实现hasNext, next, remove方法。
- public interface Iterator<E> {
- boolean hasNext();
- E next();
- void remove();
- }
routeros
Comments