设计模式中的第二类是结构型模式,共7种:
合成、适配器、装饰器、享元、门面(外观)、代理、桥梁
本篇介绍其前4种 。
Componsite
合成模式:
1 合成模式属于对象的结构模式,又叫做整体--部分模式, 合成模式将对象组织到树形结构中,可以用来描述整体与部分的关系
2 合成模式通常为树形结构,其中包括了树枝节点和树叶节点。树枝节点可以有子节点(树叶节点),树叶节点无子节点。
3 树枝节点维护树叶节点的聚集与操作。
Component 抽象组件类
package com.jelly.mypattern.composite;
/**
* 抽象构件
* 这是一个抽象角色,它给参与组合的对象定义出公共的接口及默认行为
*/
public interface Component {
//示例操作方法
public void sampleOperation();
//返回自己
public Composite getComposite();
}
Composite 树枝package com.jelly.mypattern.composite;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 树枝组件
* 可以有子节点--树枝或树叶节点
* @author jelly
*/
public class Composite implements Component{
private List<Component> comList=new ArrayList<Component>();
//操作方法
@Override
public void sampleOperation() {
for(Component component :comList){
component.sampleOperation();
}
}
//返回自身
@Override
public Composite getComposite() {
return this;
}
/**
* 管理聚集的方法 添加
* @param component
*/
public void add(Component component){
comList.add(component);
}
/**
* 管理聚集的方法 删除
* @param component
*/
public void remove(Component component){
comList.remove(component);
}
/**
* 返回管理聚集的迭代器对象
* @return
*/
public Iterator<Component> iterator(){
return comList.listIterator();
}
}
Leaf 树叶
package com.jelly.mypattern.composite;
/**
* 树叶组件
* @author jelly
*
*/
public class Leaf implements Component{
@Override
public void sampleOperation() {
System.out.println("leaf some operation...");
}
@Override
public Composite getComposite() {
return null;
}
}
客户端测试代码
package com.jelly.mypattern.composite;
/**
* 客户端测试代码
* @author jelly
*
*/
public class CompositeTest {
public static void main(String[] args) {
Component com=new Composite();
Composite componsite= com.getComposite();
Component leaf1=new Leaf();
Component leaf2=new Leaf();
Component leaf3=new Leaf();
Component leaf4=new Leaf();
componsite.add(leaf1);
componsite.add(leaf2);
Component comsite=new Composite();
comsite.getComposite().add(leaf3);
comsite.getComposite().add(leaf4);
componsite.add(comsite);
componsite.sampleOperation();
}
}
Adapter
适配器模式:
将一个类的接口变成客户端期望的另一种接口,使得原本因接口不匹配而不能一起工作的两个类能够在一起工作,解决接口不兼容的问题。
1 适配器模式分为类的适配和对象的适配2种方式,前者采用继承,后者采用引用关联。两种方式中,后者更为常见、灵活、易于扩展。
2 适配器负责将原接口向目标接口转换、靠拢,倾向于目标接口,适配过程中可能会补充原接口没有的方法。
3 例子,从 Iterator 到Enumerator接口的适配: Itermeration 。 从 Enumerator 到Iterator 接口的适配:Enuterator
4 缺省适配器模式( DefaultAdapter Pattern) 也属于适配器模式(java awt/swing 类库十分常见的模式),缺省适配器提供的父接口中所有方法的空实现(称为钩子方法)。
子类中可以通过继承缺省适配器,而不是父接口,然后覆盖几个自己关注的钩子方法就可以实现自己的业务需求。
Itermeration 适配器
package com.jelly.mypattern.adapter;
import java.util.Enumeration;
import java.util.Iterator;
/**
* Itermeration
* 从 Iterator 到Enumerator 的适配。
* Itermeration 名称取自Iterator的前部分和Enumeration的后部分
* @author jelly
*
*/
public class Itermeration<E> implements Enumeration<E> {
private Iterator<E> it;
public Itermeration(Iterator<E> it) {
this.it=it;
}
@Override
public boolean hasMoreElements() {
return it.hasNext();
}
@Override
public E nextElement() {
return it.next();
}
}
Enuterator 适配器package com.jelly.mypattern.adapter;
import java.util.Enumeration;
import java.util.Iterator;
/**
* Enuterator
* 从Enumerator 到Iterator 的适配。
* Enuterator 名称取自Enumerator的前部分和Iterator的后部分
* @author jelly
*
*/
public class Enuterator<E> implements Iterator<E>{
private Enumeration<E> enu;
public Enuterator(Enumeration<E> enu ) {
this.enu=enu;
}
@Override
public boolean hasNext() {
return enu.hasMoreElements();
}
@Override
public E next() {
return enu.nextElement();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
java I/O库中的设计 --两大对称与两大模式
两大对称: 1 输入与输出的对称 reader与writer ,inputStream与outputStream
2 字节流与字符流的对称 reader 与inputStream ,writer与outputStream
两大模式:装饰模式与适配器模式
如
BufferedReader、 BufferInputStream 、LineNumberInputStream 等 采用了装饰模式。
ByteArrayInputStream 、BufferedReaderInputStream、 InputStreamReader、 OutputStreamWriter 等均采用了适配器模式。
Decorator
装饰模式:
以客户端透明的方式扩展对象的功能,是继承关系的一种替代方案
1 装饰器通常与被装饰者实现相同的接口,并持有被装饰者的对象引用
2 装饰器在不改变原有接口的基础上进行功能的增强(称为纯粹的装饰器)
3 大多数情况下装饰器在增强功能的同时还会新增新的方法,称为非纯装饰器。
如JDK类库中BufferedReader 是reader的装饰类,增强了reader的功能,
但同时也引加入了一个新的readLine方法,使得BufferedReader 不能够使用父类Reader来引用自身。这种现象在jdk io类库中十分常见。
对于装饰器类而言,纯粹的装饰类十分少见,非纯装饰类十分常见,它们处于装饰模式与适配器模式之间(尽管如此我们依然称它为装饰器类)
它们含有的新方法越多,则它离装饰模式越远,离适配器模式越近;含有的新方法越少, 则离装饰器模式越近,离适配器模式越远
IComponent 抽象组件 接口
package com.jelly.mypattern.decorator;
/**
* 抽象组件
* @author jelly
*
*/
public interface IComponent {
/**
* 组件显示 通知消息
* @param msg
*/
public void showMsg(String msg);
/**
* 组件显示 警告消息
* @param name
*/
public void showWarning(String warning);
}
Componet具体的组件类package com.jelly.mypattern.decorator;
/**
* 具体的某个组件 实现IComponent接口
* @author jelly
*
*/
public class Component implements IComponent{
@Override
public void showMsg(String msg) {
System.out.println("message: "+msg);
}
@Override
public void showWarning(String warning) {
System.out.println("warning: "+warning);
}
}
ComponentDecorator 装饰器package com.jelly.mypattern.decorator;
/**
* ComponentDecorator 类
* 是 Componet的装饰类,与Component类实现相同的接口,
* 并在后者的基础上进行功能的增强
* @author jelly
*
*/
public class ComponentDecorator implements IComponent{
private Component component;
public ComponentDecorator(Component component) {
this.component=component;
}
@Override
public void showMsg(String msg) {
System.out.println("please read the message .");
component.showMsg(msg);
}
@Override
public void showWarning(String warning) {
component.showWarning(warning);
System.out.println("your alarm sounded!!!");
}
}
客户端测试代码
package com.jelly.mypattern.decorator;
/**
* 客户端测试类
* @author jelly
*
*/
public class DecoratorTest {
/**
* Decorator
* 装饰模式:
* 1 装饰器通常与被装饰者实现相同的接口,并持有被装饰者的对象引用
* 2 装饰器在不改变原有接口的基础上进行功能的增强(称为纯粹的装饰器)
* 3 大多数情况下装饰器在增强功能的同时还会新增新的方法,称为非纯装饰器。
* 如JDK类库中BufferedReader 是reader的装饰类,增强了reader的功能,
* 但同时也引加入了一个新的readLine方法,使得BufferedReader 不能够使用父类Reader
* 来引用自身。这种现象在jdk io类库中是否常见。
* 对于装饰器类而言,纯粹的装饰类十分少见,非纯装饰类十分常见,它们处于装饰模式与适配器模式之间(尽管如此我们依然称它为装饰器类)
* 它们含有的新方法越多,则它离装饰模式越远,离适配器模式越近;含有的新方法越少,则离装饰器模式越近,离适配器模式越远。
*
* @param args
*/
public static void main(String[] args) {
Component component=new Component();
component.showMsg("Goods morning boys and girls!");
component.showWarning("Hurry up, you're going to be late. ");
System.out.println("----------");
ComponentDecorator comDecorator=new ComponentDecorator(component);
comDecorator.showMsg("Goods morning boys and girls!");
comDecorator.showWarning("Hurry up, you're going to be late. ");
}
}
FlyWeight
享元模式
1 当应用系统中存在大量可共享的微小的对象时,可以考虑使用享元模式
2 享元模式需要一个享元工厂来维护享元对象的集合,该工厂通常是单例的。
3 享元对象之所以可以被很多客户端共享,是因为它们只含只含有可共享的状态
4 享元模式要求享元对象必须是可共享的而不是状态不变的 (状态可变,但不能受环境影响)
Word 字类 --享元类
package com.jelly.mypattern.flyWeight;
/**
*
* ‘字 ’ 类
* @author jelly
*
*/
public class Word {
//内蕴状态 共享的 不允许外部修改,
private String letters;//组成单词的字母
public Word(String letters) {
this.letters=letters;
}
/**
* 显示‘字’ ,size 是外蕴状态可以在方法中传入,但方法中不能修改享元实体的内蕴状态
* @param size
*/
public void display(int size){
System.out.println("【"+letters+"】, display in "+size+" px");
}
}
WordFacotry 类--享元工厂
package com.jelly.mypattern.flyWeight;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 生产 ‘字’ 的工厂
* @author jelly
*
*/
public class WordFactory {
private static WordFactory wordFactory=new WordFactory();
private Map<String,Word> wordCache=new HashMap<String,Word>();
/**
* 私有化构造函数
*/
private WordFactory(){
}
/**
* 暴露一个静态工厂方法,返回自身的唯一实例
* 享元工厂
* @return
*/
public static WordFactory getInstance(){
return wordFactory;
}
/**
* 生产 ‘字’ 的方法 线程同步方法
* @param letters
* @return
*/
public synchronized Word getWord(String letters){
Word word=wordCache.get(letters);
if(word==null){
word=new Word(letters);
wordCache.put(letters, word);
}
return word;
}
//遍历显示缓存池中所有的享元对象。
public void dispayAllWord(){
Set<Entry<String, Word>> entrySet= wordCache.entrySet();
for(Entry<String, Word> en: entrySet){
System.out.println(en.getKey()+"-->"+en.getValue());
}
}
}
package com.jelly.mypattern.flyWeight;
public class FlyWeightTest {
/**
* 享元模式
* 1 当应用系统中存在大量可共享的微小的对象时,可以考虑使用享元模式
* 2 享元模式需要一个享元工厂来维护享员对象的集合,该工厂通常是单例的。
* 3 享元对象之所以可以被很多客户端共享,是因为它们只含只含有可共享的状态
* 4 享元模式要求享元对象必须是可共享的而不是状态不变的。
*/
public static void main(String[] args) {
WordFactory factory=WordFactory.getInstance();
Word word1=factory.getWord("hello");
word1.display(10);
Word word2=factory.getWord("hello");
word2.display(12);
Word word3=factory.getWord("good");
word3.display(13);
System.out.println("word1 的内存地址:"+word1);
System.out.println("word2 的内存地址:"+word2);
if(word1==word2){
//如果内存地址相等,说明从工厂中得到的同一个 共享对象 (享元对象)
System.out.println("从工厂中得到的同一个共享对象 (享元对象)");
}
factory.dispayAllWord();
}
}
。。。。。。