zoukankan      html  css  js  c++  java
  • DecoratorPattern(23种设计模式之一)


    参考书籍:设计模式-可复用面向对象软件基础(黑皮书)

    书中写到,装饰者模式的意图是动态的给对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。装饰者模式的另一个别名是包装器Wrapper

    学习知识常常需要摆脱抽象的理论带给我们的不便,那么最好的方式就是从实践中去理解知识,下面我从传统模式一步一步变换到装饰者模式,这样装饰者模式的好处暴露无遗

    模拟QQ秀这一穿衣功能

    先看一组代码

    传统类

    package DecoratorPattern;
    public class Person {
    	private String name;
    	public Person(String name){
    		this.name = name;
    	}
    	public void wearTshirt(){
    		System.out.println("T恤");
    	}
    	public void wearJeans(){
    		System.out.println("牛仔裤");
    	}
    	public void wearSneakers(){
    		System.out.println("球鞋");
    	}
    	public void wearSuit(){
    		System.out.println("西装");
    	}
    	public void wearTrousers(){
    		System.out.println("西裤");
    	}
    	public void wearLeatherShoes(){
    		System.out.println("皮鞋");
    	}
    	public void show(){
    		System.out.println("装扮的" + name);
    	}
    }
    

    测试类(客户端类)

    package DecoratorPattern;
    public class Test {
    	public static void main(String[] args) {
    		Person zs = new Person("张三");	
    		System.out.println("第一种装扮:");
    		zs.wearTshirt();
    		zs.wearJeans();
    		zs.wearSneakers();
    		zs.show();	
    		System.out.println("
    第二种装扮:");
    		zs.wearSuit();
    		zs.wearTrousers();
    		zs.wearLeatherShoes();
    		zs.show();
    	}
    }
    

    上述代码存在着明显的缺陷,如果现需要不断添加新的衣服,那么就需要频繁的更改原有类Person,这不符合设计原则

    现在做一个简单的变化,将展示与穿衣服分开

    类图

    新的人类

    package DecoratorPattern;
    public class NewPerson {
    	private String name;
    	public NewPerson(String name){
    		this.name = name;
    	}
    	public void show(){
    		System.out.println("装扮的" + name);
    	}
    }
    

    抽象服饰类

    package DecoratorPattern;
    public abstract class Finery {
    	public abstract void show();
    }
    

    具体服饰类

    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class Jeans extends Finery{
    	public void show() {
    		System.out.println("牛仔裤");	
    	}
    }
    
    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class LeatherShoes extends Finery {
    	public void show() {
    		System.out.println("皮鞋");	
    	}
    }
    
    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class Sneakers extends Finery {
    	public void show() {
    		System.out.println("球鞋");	
    	}
    }
    
    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class Suit extends Finery {
    	public void show() {
    		System.out.println("西装");
    	}
    }
    
    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class Trousers extends Finery {
    	public void show() {
    		System.out.println("西裤");	
    	}
    }
    
    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class TShirts extends Finery{
    	public void show() {
    		System.out.println("T恤");
    	}	
    }
    

    测试类

    package DecoratorPattern;
    import DecoratorPattern.FineryImpl.Jeans;
    import DecoratorPattern.FineryImpl.LeatherShoes;
    import DecoratorPattern.FineryImpl.Sneakers;
    import DecoratorPattern.FineryImpl.Suit;
    import DecoratorPattern.FineryImpl.TShirts;
    import DecoratorPattern.FineryImpl.Trousers;
    public class Test1 {
    	public static void main(String[] args) {
    		NewPerson zs = new NewPerson("张三");
    		System.out.println("第一种装扮:");
    		Finery tx = new TShirts();
    		Finery nzk = new Jeans();
    		Finery ax = new Sneakers();	
    		tx.show();
    		nzk.show();
    		ax.show();
    		zs.show();	
    		System.out.println("
    第二种装扮:");
    		Finery xz = new Suit();
    		Finery xk = new Trousers();
    		Finery bx = new LeatherShoes();	
    		xz.show();
    		xk.show();
    		bx.show();
    		zs.show();
    	}
    }
    

    上述解决方式,虽然实现了设计模式的开闭原则,但是依然存在着严重的问题

    • 类繁多,这样每增加一个服饰就要增加一个类,不方便
    • 展示复杂,我们期望的是内部组装完毕再展示出来

    应用装饰者模式,解决如上问题

    装饰者模式结构

    参与者

    Component:组件
    ConcreteComponent:具体组件
    Decorator:抽象装饰类
    ConcreteDecorator:具体装饰类

    类图

    外观抽象类

    package DecoratorPattern;
    public abstract class Appearance {
    	public abstract void show();
    }
    

    package DecoratorPattern;
    public class Person extends Appearance {
    	private String name;
    	public Person(String name){
    		this.name = name;
    	}
    	public void show() {
    		System.out.println("装扮的" + name);
    	}
    }
    

    抽象装饰

    package DecoratorPattern;
    public abstract class Finery extends Appearance {
    	protected Appearance component;
    	public void Decorate(Appearance component){
    		this.component = component;
    	}
    	public void show(){
    		if(component != null){
    			component.show();
    		}
    	}
    }
    

    具体装饰

    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class Jeans extends Finery {
    	public void show(){
    		super.show();
    		System.out.println("牛仔裤");
    	}
    }
    
    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class Sneakers extends Finery {
    	public void show(){
    		super.show();
    		System.out.println("球鞋");
    	}
    }
    
    package DecoratorPattern.FineryImpl;
    import DecoratorPattern.Finery;
    public class TShirt extends Finery {
    	public void show(){
    		super.show();
    		System.out.println("T恤");
    	}
    }
    

    测试类

    package DecoratorPattern;
    import DecoratorPattern.FineryImpl.Jeans;
    import DecoratorPattern.FineryImpl.Sneakers;
    import DecoratorPattern.FineryImpl.TShirt;
    public class Test {
    	public static void main(String[] args) {
    		Person xc = new Person("小菜");
    		System.out.println("第一种装扮:");
    		
    		Sneakers ax = new Sneakers();
    		Jeans nzk = new Jeans();
    		TShirt tx = new TShirt();
    		
    		tx.Decorate(xc);
    		nzk.Decorate(tx);
    		ax.Decorate(nzk);
    		
    		ax.show();
    	}
    }
    


    待续


  • 相关阅读:
    转:页面刷新方法
    CSS 浏览器兼容与解析
    转XML格式与DataTable、DataSet、DataView格式的转换
    好文共欣赏--发布收藏
    利用HttpWebRequest自动抓取51la统计数据
    Asp.net中多语言的实现
    转 启用IIS的Gzip压缩
    在asp.net web 程序中使用Sqlite数据库
    cte+xml
    trace (转)
  • 原文地址:https://www.cnblogs.com/1996jiwei/p/6711283.html
Copyright © 2011-2022 走看看