软件构造(3)复用——构造型模式

本文为4.3部分(Deisin Patterns for Reuse)的笔记

设计模式更强调多个**类**、**对象**之间的**关系**和**交互**过程

结构型模式(Structural patterns)

1 适配器模式(Adapter)

适用场景

类之间的接口不兼容

思想

通过增加一个接口,将实现的子类封装起来,让client面向接口编程(相当于一根HDMI的数据线想接一个VGA的接口,那么就需要一个HDMI转VGA的转接头)

可以设计这样一个类C来“连接”两个不兼容的类A和B(B实现A),(1)C的前置条件与A需要实现的方法的前置条件完全一致,而在C的内部,(2)可以将传入的参数转化成符合B的方法的前置条件,(3)通过B来满足A的后置条件(可以继承,也可以委托delegate)。综上,可以发现B消失了,而A通过C这一转接器实现了功能(由上述三个条件可知)

具体实现
interface S{//需要修改功能的类
	void d(int x,int y);
}
class R implements S{
	//adaptor
	void d(int x, int y){//外表
		new L().b(x+y,x-y,x*y);//内部(委托)
	}
}
/*
class R implements S entends C{
	//adaptor
	void d(int x, int y){
		...
		super.Func(param1,param2);
	}
	
}
*/
class L{//可以调用或者继承的类
	void b(int a,int b,int c){...}
}
class Client{
	S s = new R();
	public d(){
		s.d(x,y);
	}
}

这里需要用类L的b方法来实现类R中的d方法,从而使得Client可以正常运行,那么这里用adaptor是一个可行的方法。(疑惑:这里需要S必须是一个接口吗,为什么?我认为当S是一个具体类时,也可以通过定义一个S的子类T,然后在T中实现转接亦可,但只能用委托,而不能使用继承了。)

总结

所谓转接,外符于外,内适于内,内外不一,实现第一。

2 装饰器模式(Decorator)

该模式即lab3知道手册中的方法6

适用场景

需要用许多子类的任意组合来实现某一特殊类

思想

装饰,可以看做用多彩涂料来铺色。当然,首先我们需要一张白纸,然后根据不同颜色,一层一层的往纸上铺,可以有这种思想,我在铺红色之前,要先铺绿色;又我在铺绿色之前,要先铺灰色。那么,我们可以从灰色开始上色,然后绿色,再红色。
装饰,亦可以看做是给冰淇淋上球。首先我们需要一个,然后往上面上爱吃的口味。

这里的白纸可以是一个实现基础功能的一个基础类,而上不同色上不同口味球是一系列要被调用的特殊类

具体实现

这里用冰淇淋上球举例

public interface IceCream{
	void AddTopping();
}
//基础类
public class PlainIceCream implements IceCream{
	@override
	public void AddTopping(){
		cout<<"Plain";
	}
}
//装饰器基类(抽象类,那么多球也总有一些相似之处吧?因此,定义一个基类更好)
public abstract class ToppingDecorator implements IceCream{
	protected final IceCream **input**;//aggregation形式的委托
	public ToppingDecorator(IceCream i){
		this.input = i;
	}
	public abstract void AddTopping();//抽象方法,留给具体的装饰器类来实现
}
public class FlowerTopping extends ToppingDecorator{
	public FlowerTopping(IceCream i){
		super(i);//实现父类的一个好处,可以将共性的实现在父类实现,一劳永逸
	}
	@override
	public void AddTopping(){
		input.AddTopping();
		cout<<"Flower";
	}
}
public class IphoneTopping extends ToppingDecorator{
	public iphoneTopping(IceCream i){
		super(i);//实现父类的一个好处,可以将共性的实现在父类实现,一劳永逸
	}
	@override
	public void AddTopping(){
		input.AddTopping();
		cout<<"iphone";
	}
}
public class MoneyTopping extends ToppingDecorator{
	public MoneyTopping(IceCream i){
		super(i);//实现父类的一个好处,可以将共性的实现在父类实现,一劳永逸
	}
	@override
	public void AddTopping(){
		input.AddTopping();
		cout<<"Money";
	}
}
//Client
public Client{
	public static void main(String[] args){
		IceCream a = new PlainIceCream();
		IceCream b = new IphoneIceCream(a);//在筒上放一个iphone
		IceCream c = new CandyIceCream(b);//在放一颗糖果
		IceCream d = new MoneyIceCream(c);//再放一点money
		//黑暗料理。。。
		d.AddTopping();//recursive实现
		//**another realization**
		IceCream toppingIceCream = new MoneyTopping(new IphoneTopping(new CandyTopping(new PlainIceCream())));
		toppingIceCream.AddTopping();//recursive too

第一种实现可以在加money之前加点别的,或者干脆不加money,更灵活;而第二种实现不行,不喜欢money也不行~,更直接。

总结

一个白板,多种色彩,妞妞妞妞,递归实现(recursive)。

3 外观模式(Façade)

适用场合

客户端需要通过一个简化的接口来访问复杂系统内的功能
便

思想
Wrap a complicated subsystem with a simpler interface.//封装
This reduces the learning curve.//便于学习使用
It also decoupling the subsystem from its potentially many clients//解耦
Façade pattern is applied for similar kind of interfaces, its purpose is to provide a single interface rather than multiple interfaces that does the similar kind of jobs.

提供一个统一的接口来取来一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用,便于客户端学习,解耦。

具体实现
public class Loader(){...}
public class Chess{
	public static Loader Chessloader(){...}
	public void ChessVA(String[] names,Loader ldr){...}
	public void ChessVB(String[] names,Loader ldr){...}
	public void ChessVC(String[] names,Loader ldr){...}
}
public class Go{
	public static Loader Goloader(){...}
	public void GoVA(String[] names,Loader ldr){...}
	public void GoVB(String[] names,Loader ldr){...}
	public void GoVC(String[] names,Loader ldr){...}
}
public class Monopole{
	public static Loader Monoloader(){...}
	public void MonoVA(String[] names,Loader ldr){...}
	public void MonoVB(String[] names,Loader ldr){...}
	public void MonoVC(String[] names,Loader ldr){...}
}
public HelperFacade{
	public static void goandplay(Types type, Versions version, String[] names){
		Loader ldr = null;
		switch(type){
		case CHESS:
			ldr = chess.Chessloader();//静态工厂方法
			Chess chess = new Chess();
			switch(version){
				case A:
					chess.ChessVA(names);
					break;
				case B:
					chess.ChessVB(names);
					break;
				...
			}
			break;
		case GO:
			Go go = new Go();
			ldr = go.Goloader();
			switch(version){
			...
			}
			break;
		case MONOPOLE:
			...
			break;

public static enum Types {CHESS,GO,MONOPOLE;}//采用枚举
public static enum Versions {A,B,C;}
}


如上设计,下面来看看使用Facade的效果。
**不使用Facade模式**:
String names = {"Giao","Skr",...};
Loader ldr = Chess.Chessloader();
Chess chess = new Chess();
chess.ChessVA(names, ldr);

**使用Facade模式**:
String names = {"Giaoi","Skr",...};
HelperFacade.goandplay(HelperFacade.Types.CHESS,HelperFacade.Versions.A,names);
//Go your game and have fun!
总结

可能看到使用Facade时,客户端的代码也并不是十分简洁,但将具体数据放在相应位置,你会发现,整个操作其实一句话就搞定了,这就是外观模式的魅力(i了i了).
杂乱无章的电线没错,但干净整洁的插座更受人喜欢。——鲁 迅(doge)

结尾

相信到了这里,你应该体会到了如何从程序的结构上解决模块之间的耦合问题,在另一模式(行为模式)中,你会看到从一个角度如何考虑解耦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值