【软件构造】6.2 面向可维护性的设计模式

面向可维护性的设计模式

1.创建型模式

关于如何“创建类的新实例”的模式

1.1 工厂方法模式

当client不知道要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。
定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。
在这里插入图片描述
在这里插入图片描述
静态工厂方法:
在这里插入图片描述
优点:避免将代码与具体的实现类(因具体应用而不同)绑定。代码对接口编程,因而适用于所有的实现类。
缺点:为了创建需要的具体的对象,客户端必须知道Creator抽象类的子类。

1.2 抽象工厂模式

提供接口以创建一组相关/相互依赖的对象,但不需要指明其具体类。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品的实例),得到的结果是:多个不同产品的object,各产品创建过程对client可见,但“搭配”不能改变。
使用factory method,不能保证固定搭配
抽象工厂与工厂方法:

抽象工厂工厂方法
创建一组有关联的对象创建一个对象
一组factory方法一个factory方法
使用组合/委派使用继承/子类型

(抽象工厂把创建对象的过程委派给其他的类)

1.3 构造器模式

创建复杂对象,其中包含多个组成部分
例:
该Pizza产品的part是以三个属性的形式体现,其builder就相当于给三个属性赋值。

/*Product*/
class Pizza{
	private String dough = "";
	private String sauce = "";
	private String topping = "";
	
	public void setDough(String dough){
		this.dough = dough;
	}
	public void setSauce(String sauce){
		this.sauce = sauce;
	}
	public void setTopping(String topping){
		this.topping = topping;
	}
}

Builder抽象类有三个抽象方法,分别创建三个part

/*"Abstract Builder"*/
abstract class PizzaBuilder{
	protected Pizza pizza;
	public Pizza getPizza(){
		return pizza;
	}
	public void createNewPizzaProduct(){ 
		pizza = new Pizza(); 
	} 
	public abstract void buildDough(); 
	public abstract void buildSauce(); 
	public abstract void buildTopping();
}

具体的builder子类

/* "ConcreteBuilder 1" */ 
class SpicyPizzaBuilder extends PizzaBuilder { 
	public void buildDough() { 
		pizza.setDough("pan baked"); 
	} 
	public void buildSauce() { 
		pizza.setSauce("hot"); 
	} 
	public void buildTopping() { 
		pizza.setTopping("pepperoni+salami"); 
	} 
} 
/* "ConcreteBuilder 2" */ 
class HawaiianPizzaBuilder extends PizzaBuilder { 
	public void buildDough() { 
		pizza.setDough("cross"); 
	} 
	public void buildSauce() { 
		pizza.setSauce("mild"); 
	} 
	public void buildTopping() { 
		pizza.setTopping("ham+pineapple"); 
	} 
}
/* "Director" */ 
class Waiter { 
	private PizzaBuilder pizzaBuilder; 
	public void setPizzaBuilder(PizzaBuilder pb) { 
		pizzaBuilder = pb; 
	} //定义要delegate的builder
	public Pizza getPizza() { 
		return pizzaBuilder.getPizza(); 
	} //得到最终builder的结果
	public void constructPizza() { 
		pizzaBuilder.createNewPizzaProduct(); 
		pizzaBuilder.buildDough(); 
		pizzaBuilder.buildSauce(); 
		pizzaBuilder.buildTopping(); 
	} //具体构建各部分
}
/* A customer ordering a pizza. */ 
public class PizzaBuilderDemo { 
	public static void main(String[] args) { 
		Waiter waiter = new Waiter(); 
		PizzaBuilder hawaiianPizzabuilder = new HawaiianPizzaBuilder(); 
		PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();
		//client使用不同的builder子类创建不同的产品
		
		waiter.setPizzaBuilder( hawaiianPizzabuilder ); 
		//建立waiter和builder的delegation关系
		waiter.constructPizza(); 
		Pizza pizza = waiter.getPizza();
	}
}

在这里插入图片描述

与抽象工厂模式的对比:

抽象工厂模式创建的不是一个完整产品,而是“产品族”。得到多个不同产品的实例object,各产品创建过程对client可见,但“搭配”不能改变。
构造器模式创建的是一个完整的产品,有多个部分组成,client不需了解每个部分是怎么创建、各个部分怎么组合,最终得到一个产品的完整object

与模板模式的对比:

模板模式:行为类模式。复用算法骨架,强调步骤的次序
构造器模式:创建型模式。将一个复杂对象的构造方法与对象内部的具体表示分离出来,灵活扩展,适应变化。

2.结构型模式

2.1 桥接模式

主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展。
要素:
1.抽象类(Abstraction):维护对行为实现(implementation)的引用。
2.Refined Abstraction:Abstraction的子类
3.Implementor:行为实现类接口
4.ConcreteImplementor:Implementor的子类
在这里插入图片描述
例:
Implementor:

public interface DrawAPI { 
	public void drawCircle(int radius, int x, int y); 
} 

ConcreteImplementor:

public class DrawRedCircle implements DrawAPI { 
	@Override 
	public void drawCircle(int radius, int x, int y) { 
		System.out.println(“Color: red " + radius + x + y); 
	} 
} 
public class DrawGreenCircle implements DrawAPI { 
	@Override public void drawCircle(int radius, int x, int y) { 
		System.out.println(“Color: green " + radius + x + y); 
	} 
}

Abstraction:

public abstract class Shape { 
	protected DrawAPI drawAPI; //永久保存delegation并在其他场合使用
	protected Shape(DrawAPI drawAPI){ //动态传入,建立delegation link
		this.drawAPI = drawAPI; 
	} 
	public abstract void draw(); 
} 

Refined Abstraction

public class Circle extends Shape {
	private int x, y, radius;
	public Circle(int x, int y, int radius, DrawAPI drawAPI) { 
		super(drawAPI); 
		this.x = x;  
		this.y = y;  
		this.radius = radius; 
	} 
	public void draw() { 
		drawAPI.drawCircle(radius,x,y); //将draw这个责任delegate到drawAPI这个接口的具体实例去执行
	}
}

在这里插入图片描述

与Strategy模式的对比:

Bridge:结构型模式,强调双方的run time delegation linking
一个类A的对象中有其他类B的对象作为其组成部分,A的对象具体绑定到B的哪个具体子类,在运行时通过delegation加以组合, 并永久保存这种delegation关系。
Strategy:行为类模式,强调一方run-time使用另一方的“算法”
“算法”通常实现为“类的某个方法”的形式, strategy的目的并非在“调用算法的类”与“被调用算法所在的类”之间建立起永久联系,而只是帮助前者临时使用后者中的“算法”,前者无需永久保存后者的实例。

2.2 代理模式

在client和不希望被直接访问(敏感/私密/访问代价高)的对象之间建立防火墙。
例:

public interface Image { 
	void display(); 
}
public class RealImage implements Image {
	private String fileName; 
	public RealImage(String fileName){ 
		this.fileName = fileName; 
		loadFromDisk(fileName); 
	}
	
	@Override 
	public void display() {}
	private void loadFromDisk(String fileName){}
	//每次创建都要 从磁盘装载,代价高
}

public class ProxyImage implements Image { 
	private Image realImage; 
	private String fileName;
	public ProxyImage(String fileName){ 
		//不需要在构造的时候从文件装载
		this.fileName = fileName; 
	}
	@Override 
	public void display() { 
		if(realImage == null){ 
		//如果display的时候发现没有装载,则再delegation
			realImage = new RealImage(fileName); 
			//Delegate到原来的类来完成具体装载
		} 
		realImage.display(); 
	}
}

Client: 
Image image = new ProxyImage(“pic.jpg"); 
image.display(); 
image.display(); 

在这里插入图片描述

与Adapter模式的对比:

Adapter::消除不兼容,目的是B以客户端期望的统一的方式与A建立起联系。
Proxy: 目的:隔离对复杂对象的访问,降低难度/代价,定位在“访问/使用行为”

2.3 组合模式

组合模式依据树形结构来组合对象,用来表示部分以及整体层次。它创建了对象组的树形结构。
在这里插入图片描述
例:

public interface Employee { 
	public void add(Employee e); 
	public void remove(Employee e); 
	public List<Employee> getSubordinates(); 
}
public class ConcreteEmployee implements Employee{ 
	private String name; 
	private String position; 
	private List<Employee> subordinates;
	public Employee(String name) { 
		this.name = name; subordinates = new ArrayList<Employee>(); 
	} 
	public void add(Employee e) { 
		subordinates.add(e); 
	} 
	public void remove(Employee e) { 
		subordinates.remove(e); 
	} 
	public List<Employee> getSubordinates(){ 
		return subordinates; 
	}
}

public class CEO extends ConcreteEmployee { 
	//Special fields or methods 
}
public class Clerk extends ConcreteEmployee { 
	//Special fields or methods 
}
Employee CEO = new CEO ("John"); 
Employee headSales = new ConcreteEmployee("Robert"); 
Employee clerk1 = new Clerk("Laura"); 
Employee clerk2 = new Clerk("Bob");

CEO.add(headSales); 
CEO.add(clerk1); 
clerk1.add(clerk2);
System.out.println(CEO); 
for (Employee headEmployee : CEO.getSubordinates()) { 
	System.out.println(headEmployee); 
		for (Employee employee : headEmployee.getSubordinates()) { 
			System.out.println(employee); 
		} 
}
与Decorator的区别:

Composite: 目的是在同类型的对象之间建立起树型层次结构,一个上层对象可包含多个下层对象
叶节点的实体与组合实体相同;组合结构中所有元素具有相同接口
Decorator: 强调的是同类型对象之间的“特性增加”问题

3.行为式模式

3.1 Observer

dependent的状态必须与master的状态一致
四种对象:
抽象主体:管理dependents的列表,master状态变化时通知他们
抽象观察者:定义更新dependents的方式
具体主体:管理dependents的信息,master状态变化时通知他们
具体观察者:收到更新状态的信息之后更新状态
在这里插入图片描述
代码:

public class Subject {
	private List<Observer> observers = new ArrayList<Observer>(); //维持一组“对自己感兴趣的”对象
	private int state;
	public int getState() {return state;}
	public void setState(int state) { 
		this.state = state; 
		notifyAllObservers(); //在自己状态变化时,通知所有“粉丝”
	}
	public void attach(Observer observer){observers.add(observer);}
	//允许“粉丝”调用该方法向自己注册,将其加入队列
	private void notifyAllObservers(){ 
		for (Observer observer : observers) { 
			observer.update(); //callbck调用“粉丝”的update操作,向粉丝“广播”自己的变化
		} 
	} 
}
public abstract class Observer { 
	protected Subject subject; 
	public abstract void update(); 
}
public class BinaryObserver extends Observer{
	public BinaryObserver(Subject subject){ 
		this.subject = subject; 
		this.subject.attach(this); 
	}
	
	@Override 
	public void update() { //这个方法被“偶像”回调
		System.out.println( "Binary String: " + Integer.toBinaryString( subject.getState() ) ); 
	}
}
public class ObserverPatternDemo {
	public static void main(String[] args) { 
		Subject subject = new Subject();
		new HexaObserver(subject); 
		new OctalObserver(subject); 
		new BinaryObserver(subject);
		System.out.println("First state change: 15"); s
		ubject.setState(15); 
		System.out.println("Second state change: 10"); 
		subject.setState(10);//没有调用observer行为的代码
	}
}

构建了一到多的依赖关系,将被观察者的状态与观察者连接起来。
优点:
1.主体与观察者之间的低耦合
2.允许广播
3.观察者更新状态不受主体的控制
java提供了Observer(观察者)和Observable(被观察者/主体)接口

3.2 Visitor

将数据与操作分离。创建一个外部类(visitor),该类对其他类中的数据进行操作。当操作逻辑改变时,只需改变visitor类的实现。
在这里插入图片描述

/* Abstract element interface (visitable) */ 
public interface ItemElement { 
	public int accept(ShoppingCartVisitor visitor); 
}

/* Concrete element */ 
public class Book implements ItemElement{ 
	private double price; 
	... 
	int accept(ShoppingCartVisitor visitor) { 
		visitor.visit(this); //将处理数据的功能delegate到外部传入的visitor
	} 
} 

public class Fruit implements ItemElement{
	private double weight; 
	... 
	int accept(ShoppingCartVisitor visitor) { 
		visitor.visit(this); 
	} 
}
/* Abstract visitor interface */ 
public interface ShoppingCartVisitor { 
	int visit(Book book); 
	int visit(Fruit fruit); 
} 
public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {
	public int visit(Book book) { 
		int cost=0; 
		if(book.getPrice() > 50){ 
			cost = book.getPrice()-5; 
		}else 
			cost = book.getPrice(); 
		System.out.println("Book ISBN::"+book.getIsbnNumber() + " cost ="+cost); 
		return cost; 
	} 
	public int visit(Fruit fruit) { 
		int cost = fruit.getPricePerKg()*fruit.getWeight(); 
		System.out.println(fruit.getName() + " cost = "+cost); 
		return cost; 
	} 
} 
public class ShoppingCartClient {
	public static void main(String[] args) {
	ItemElement[] items = new ItemElement[]{ new Book(20, "1234"),new Book(100, "5678"), new Fruit(10, 2, "Banana"), new Fruit(5, 5, "Apple")};
	int total = calculatePrice(items); System.out.println("Total Cost = "+total);
	}
	private static int calculatePrice(ItemElement[] items) { 
		ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl(); 
		int sum=0; for(ItemElement item : items) 
			sum = sum + item.accept(visitor); 
		return sum; 
	}
}

Visitor vs Iterator
迭代器:以遍历的方式访问集合数据而无需暴露其内部表示,将“遍历”这项功能delegate到外部的iterator对象。
Visitor:在特定ADT上执行某种特定操作,但该操作不在ADT内部实现,而是delegate到独立的visitor对象,客户端可灵活扩展/改变visitor的操作算法,而不影响ADT

Strategy vs visitor
:visitor是站在外部client的角度,灵活增加对ADT的各种不同操作(哪怕ADT没实现该操作),strategy则是站在内部ADT的角度,灵活变化对其内部功能的不同配置。

3.3 Mediator

3.4 Command

3.5 职责链模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值