接上篇,本文介绍结构型模式里的组合模式、装饰模式、外观模式。
一、组合模式(Composite)
组合模式:将对象组合成树形结构,表示“部分--整体”的层次结构。最终达到单个对象和组合对象的使用具有一致性。单看这句话貌似有点抽象,其实比较简单。
以李云龙的独立团为例,目的要统计赵嘉宇一战共歼灭敌人多少个。最高的级别是团,一个团有若干个营,一个营有若干个排,一个排有若干个战士。(为了简化问题,排下面就不设行政单位了)。很自然的,李云龙给营长开会回去给老子统计。营长回去给各个排长开会,赶紧统计。排长回去问问大家,数字报上去,汇报结束。这就是典型的组合模式。
组合模式涉及到Component(部件)、Leaf(叶子)、Composite(组合对象)三个概念。其中Component是组合中的对象声明接口,实现所有类共有接口的缺省行为。本例中Component类的设计至少有三个方法:addMember()(对应某个排新来一个战士)、deleteMember(某个士兵战死了,排长要将其删除)、getKillNumber()(这是通用行为获得杀敌数)。Leaf表示爷子接点,这里的士兵就是最底层的Leaf,他没有添加member的权利。1排排长、2排排长都是leaf,他们可以添加member。每个类里应维护一个List,用于管理属于它的member。那么这个排长就属于
一种组合了。下面附个完整例子:
1、Component
public abstract class Employer {
private String name;
public void setName(String name) {
this.name = *ame;
}
public String getName() {
return this.name;
}
public abstract void add(Employer employer*;
public abstract void delete(Employer employer);
public List employers;
public void printInfo*) {
System.out.println(name);
}
public List getE*ployers() {
return this.employers;
}
}
注意:这里为什么使用absract,而不使用interface,参见上篇。
2.Leaf 这里定义的程序员和项目经理是平级的,都是给下面的
项目经理打工的,没有子节点。
public class Programmer extends Employer {
public Programmer(String name) {
setName(name);
employers = null;//程序员, 表示没有下属了
}
public void add(Employer employer) {
}
public void delete(Employer employer) {
}
}
public class ProjectAssistant extends Employer {
public ProjectAssistant(String name) {
setName(name);
employers = *ull;//项目助理, 表示没有下属了
}
public void add(Employer employer) {
}
public void delete(Employer employer) {
}
}
3.Composite 组合
public class ProjectManager extends E*ployer {
public ProjectManager(String name) {
setName(name);
employers = new A*rayList();
}
public void add(Employer employer) {
employers.add(employer);
}
public void delete(Emplo*er employer) {
employers.remove(employer);
}
}
测试代码:
public class Test {
public static void main(String[] args) {
Employer pm = new ProjectManager("项目经理");
Emplo*er pa = new ProjectAssistant("项目助理");
Employer progra*mer1 = new Programmer("程序员一");
Employer programmer2 = new Programmer("程序员二");
pm.add(pa);//为项目经理添加项目助理
pm.add(programmer2);//*项目经理*加程序员
List ems = pm.getEm*loyers();
for (Employer em : ems) {
System.out.println(em.getNam*());
}
}
}
适用性:
1.你想表示对象的部分-整体层次结构。
2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
注:组合模式可以很好的扩展,像开头说的统计歼敌数量的例子,排长和营长都是组合,但他们又是上一级的叶子,同时自己也有叶子。
另,http://blog.csdn.net/jason0539/article/details/22642281
http://blog.csdn.net/guolin_blog/article/details/9153753 可以参考辅助理解。
二、装饰模式Decorator
动态给一个对象添加额外的职责,在增加功能方面,Decorator模式比生成子类更加灵活。
参与者:
1.Component 定义一个对象接口,可以给这些对象动态添加职责。
public interface Person {
void eat();
}
2.ConcreteComponent定义一个对象,可以给这个对象添加一些职责。
public class Man implements Person {
public void eat() {
System.out.println("男人在吃");
}
}
3.Decorator 维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
public abstract class Decorator implements Person {
protected Person person;
public void setPerson(Person person) {
this.person = person;
}
public void eat() {
person.eat();
}
}
4.ConcreteDecorator向组件添加职责
public class ManDecoratorA extends Decorator {
public void eat() {
super.eat();
reEat();
System.out.println("ManDecoratorA类");
}
public void reEat() {
System.out.println("再吃一顿饭");
}
}
public class ManDecoratorB extends Decorator {
public void eat() {
super.eat();
Syst*m.out.println("===============");
System.out.println("ManDecoratorB类");
}
}
测试代码:
public class Test {
public static void main(Strin*[] args) {
Man man = new Man();
ManDecoratorA md1 = new ManDecoratorA();
ManDecoratorB md2 = new ManDecoratorB();
md1.setPerson(man);
md2.setPerson(md1);
md2.eat();
}
}
适用性:
1.在不影响其他*象的情况下,以动态、透明的方式给单个对象添加职责。
2.处理那些可以撤消的职责。
3.当不能采用生成子类的方法进行扩充时。
可以看到装饰模式可以在不创造更多的子类模式下,将对象的功能加以扩展。装饰模式和类继承的区别:
1)装饰模式是一种动态行为,对已经存在类进行随意组合,而类的继承是一种静态的行为,一个类定义成什么样的,该类的对象便具有什么样的功能,无法动态的改变。
2)装饰模式扩展的是对象的功能,不需要增加类的数量,而类继承扩展是类的功能,在继承的关系中,如果我们想增加一个对象的功能,我们只能通过继承关系,在子类中增加两个方法。
装饰与继承比较:
1装饰模式是在不改变原类文件和使用继承的情况下,动态的扩展一个对象的功能,它是通过创建一个包装对象,也就是装饰来包裹真是的对象。
2装饰模式把对客户端的调用委派给被装饰的类,装饰模式的关键在于这种扩展完全透明的。
注:有人会说这里的ManDecoratorB、ManDecoratorA还是定义了新的子类的,这是为了示例在不同的层次上定义的,如果增加一个层次的功能的话只需定义一个ManDecoratorA里的reEat()里写上就行了。可以看到最大的不同是在对原来的调用不影响,用户不知不觉调用原来的eat()其实已经多吃了两碗,哈哈。这是类的继承无法达到的。也可再看看此例:http://www.cnblogs.com/hnrainll/archive/2012/03/23/2414180.html
三、外观模式Facade
为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这些子系统更加容易使用。比如对于李云龙来说,要完成一次战役指挥,他只需发布命令:准备战斗、开火、打扫战场回家。这三个步骤,而每个步骤,具体到每个营、每个排都要做大量的准备和布置。但这些不是老李关心的。简而言之,就是把子类的一系列行为按类别封装起来,对外只提供一个统一的接口,这就是外观模式。
1、一系列的子类
public class ServiceAImpl implements ServiceA {
public void methodA() {
System.out.println("这是服务A");
}
}
public class ServiceBImpl implements ServiceB {
public void methodB() {
System.out.println("这是服务B");
}
}
public class ServiceCImpl implements ServiceC {
public void methodC() {
System.out.println("这是服*C");
}
}
2.Facade
public class Facade {
ServiceA s*;
ServiceB sb;
ServiceC sc;
public Facade() {
sa = new S*rviceAImpl();
sb = new *erviceBImpl();
sc = new ServiceCImpl();
}
public void methodA() {
sa.methodA();
sb.methodB();
}
publi* void methodB() {
s*.methodB();
sc.methodC();
}
public void methodC() {
sc.methodC();
sa.methodA();
}
}
注:就是把三个子类的方法重新封装了下,统一对外提供接口。但这个例子本身举得不太好。
测试代码:
public class Test {
public static void main(String[] args) {
ServiceA sa = new ServiceAImpl();
ServiceB sb = new ServiceBImpl();
sa.methodA();
sb.methodB();
System.out.println("========");
//facade
Facade facade = new Facade();
facade.methodA();
facade.methodB();
}
}
所以外观模式是很简单的一种,也可参见链接。
Java经典23种设计模式之结构型模式(二),布布扣,bubuko.com
Java经典23种设计模式之结构型模式(二)
原文:http://blog.csdn.net/yanzi1225627/article/details/37614029