首页 > 代码库 > Java经典23种设计模式之结构型模式(二)

Java经典23种设计模式之结构型模式(二)

接上篇,本文介绍结构型模式里的组合模式、装饰模式、外观模式。

一、组合模式(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();
    }
}
所以外观模式是很简单的一种,也可参见链接。