zoukankan      html  css  js  c++  java
  • 设计模式之装饰模式、工厂方法模式、抽象工厂模式浅析

           
    装饰模式: 动态的为对象添加附加功能,提供了一种扩展机制,比继承更具有扩展性

    简单工厂:在一个类中处理创建对象的细节

    工厂方法模式:
     *   让子类决定初始化什么样的对象,即将类的实例化推迟到子类中进行
     * 工厂方法使用继承,将对象的创建委托给子类进行创建  

     抽象工厂模式:
     *   定义了一个接口,提供了创建依赖对象的家族,但是不指定具体创建什么类型  
     * 抽象工厂使用组合概念,构建对象的家族 


    1、装饰模式

    /**
     * 设计原则: 开放-关闭原则: 对扩展开放,对修改关闭
     * 
     * 装饰模式: 动态的为对象添加附加功能,提供了一种扩展机制,比继承更具有扩展性
     * 
     * 涉及到的概念: 
     * 装饰者(为其他对象添加功能的对象)与被装饰者(被添加功能的对象)
             组合和委托可在运行时动态的加上新的行为
     * 装饰者中拥有被装饰者的超级父类,用于指向被装饰者,当对装饰者进行操作时,被装饰者即委托装饰者执行相关操作
     * 装饰者和被装饰者必须拥有相同的超级父类,用于装饰者替换被装饰者
     * 
     * 
     * 实例: 用于计算不同饮料与配料加起来的总费用 饮料: 咖啡(10元1杯)、茶叶(12元一杯)、奶茶(8元1杯) 配料:
     * 摩卡(4元1份)、蜂蜜(3元1份)、柠檬(2元1份)
     * 
     * 
     * 
     * @author Administrator
     * 
     */


    先来看饮料父类

    package com.undergrowth.decorate;
    
    /**
     * 设计原则: 开放-关闭原则: 对扩展开放,对修改关闭
     * 
     * 装饰模式: 动态的为对象添加附加功能,提供了一种扩展机制,比继承更具有扩展性
     * 
     * 涉及到的概念: 
     * 装饰者(为其他对象添加功能的对象)与被装饰者(被添加功能的对象)
             组合和委托可在运行时动态的加上新的行为
     * 装饰者中拥有被装饰者的超级父类,用于指向被装饰者,当对装饰者进行操作时,被装饰者即委托装饰者执行相关操作
     * 装饰者和被装饰者必须拥有相同的超级父类,用于装饰者替换被装饰者
     * 
     * 
     * 实例: 用于计算不同饮料与配料加起来的总费用 饮料: 咖啡(10元1杯)、茶叶(12元一杯)、奶茶(8元1杯) 配料:
     * 摩卡(4元1份)、蜂蜜(3元1份)、柠檬(2元1份)
     * 
     * 
     * 
     * @author Administrator
     * 
     */
    public abstract class Baverage {
    	/**
    	 * 用于对饮料的描述
    	 */
    	public String description;
    
    	/**
    	 * 用于计算不同饮料的价钱
    	 * 
    	 * @return
    	 */
    	public abstract double cost();
    
    	public String getDescription() {
    		return description;
    	}
    
    }
    

    用于用于子类重写的cost方法

    接下来是两种饮料 咖啡和茶叶

    package com.undergrowth.decorate;
    
    public class Coffee extends Baverage {
    
    	public Coffee(){
    		description=Coffee.class.getSimpleName();
    	}
    	
    	@Override
    	public double cost() {
    		// TODO Auto-generated method stub
    		return Price.CoffeePrice;
    	}
    
    }
    

    package com.undergrowth.decorate;
    
    public class Tea extends Baverage {
    
    	public Tea(){
    		description=Tea.class.getSimpleName();
    	}
    	
    	@Override
    	public double cost() {
    		// TODO Auto-generated method stub
    		return Price.TeaPrice;
    	}
    
    }
    


    当饮料构建完后  接下来构建配料  配料的父类

    package com.undergrowth.decorate;
    
    public abstract class IngredientBaverage extends Baverage {
    
    	public abstract String getDescription();
    	
    
    }
    

    getDescription方法抽象的原因 是为了获得更为详细的描述

    接下来是摩卡和蜂蜜的两种配料

    package com.undergrowth.decorate;
    
    public class MochaIngredient extends IngredientBaverage {
        
    	Baverage baverage;
    	
    	public MochaIngredient(Baverage baverage){
    		this.baverage=baverage;
    	}
    	
    	
    	
    	@Override
    	public String getDescription() {
    		// TODO Auto-generated method stub
    		return MochaIngredient.class.getSimpleName()+"	"+baverage.getDescription();
    	}
    
    	@Override
    	public double cost() {
    		// TODO Auto-generated method stub
    		return Price.MochaPrice+baverage.cost();
    	}
    
    }
    


    package com.undergrowth.decorate;
    
    public class HoneyIngredient extends IngredientBaverage {
    
    	Baverage baverage;
    	
    	public HoneyIngredient(Baverage baverage)
    	{
    		this.baverage=baverage;
    	}
    	
    	@Override
    	public String getDescription() {
    		// TODO Auto-generated method stub
    		return HoneyIngredient.class.getSimpleName()+"	"+baverage.getDescription();
    	}
    
    	@Override
    	public double cost() {
    		// TODO Auto-generated method stub
    		return Price.HoneyPrice+baverage.cost();
    	}
    
    }
    


    最后一个 价格常量类

    package com.undergrowth.decorate;
    
    public class Price {
    	public static final double CoffeePrice=10;
    	public static final double TeaPrice=12;
    	public static final double MochaPrice=4;
    	public static final double HoneyPrice=3;
    }
    


    测试类

    package com.undergrowth.decorate.test;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    import com.undergrowth.decorate.Coffee;
    import com.undergrowth.decorate.HoneyIngredient;
    import com.undergrowth.decorate.MochaIngredient;
    import com.undergrowth.decorate.Tea;
    
    import com.undergrowth.decorate.Baverage;
    
    public class MochaIngredientTest {
    
    	@Test
    	public void test() {
    		//现在我要2份摩卡的咖啡 算算多少钱
    		Baverage baverage=new Coffee();
    		baverage=new MochaIngredient(baverage);
    		baverage=new MochaIngredient(baverage);
    		System.out.println(baverage.getDescription()+"	价格:"+baverage.cost());
    	    
    		//一份摩卡 一份蜂蜜的茶叶
    		baverage=new Tea();
    		baverage=new MochaIngredient(baverage);
    		baverage=new HoneyIngredient(baverage);
    		System.out.println(baverage.getDescription()+"	价格:"+baverage.cost());
    	}
    
    }
    

    结果输出

    MochaIngredient	MochaIngredient	Coffee	价格:18.0
    HoneyIngredient	MochaIngredient	Tea	价格:19.0
    


    上面即使装饰模式的实例    在java类库中 装饰模式也用于很多地方  如IO流 集合

      再来看一个io流中的例子

    字符输入流装饰者  用于对输入的字符进行转换 将输入的字符全部转为大写

    package com.undergrowth.decorate.util;
    
    import java.io.FilterInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    /**
     * 字符输入流装饰者  用于对输入的字符进行转换 将输入的字符全部转为大写
     * @author Administrator
     *
     */
    public class CharacterInputStreamDecorate extends FilterInputStream {
    
    	protected CharacterInputStreamDecorate(InputStream in) {
    		super(in);
    		// TODO Auto-generated constructor stub
    	}
    
    	@Override
    	public int read() throws IOException {
    		// TODO Auto-generated method stub
    		int c=super.read();
    		return (c==-1)?c:Character.toUpperCase(c);
    	}
    
    	@Override
    	public int read(byte[] b, int off, int len) throws IOException {
    		// TODO Auto-generated method stub
    		int result=super.read(b, off, len);
    		if(result!=-1){
    			for (int i = off; i < off+result; i++) {
    				b[i]=(byte) Character.toUpperCase(b[i]);
    			}
    		}
    		return result;
    	}
    	
    	
    
    }
    


    测试类

    package com.undergrowth.decorate.util;
    
    import static org.junit.Assert.*;
    
    import java.awt.im.InputContext;
    import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    
    import org.junit.Test;
    
    public class CharacterInputStreamDecorateTest {
    
    	@Test
    	public void test() {
    		int c;
    		try {
    			String pathname="data.txt";
    			InputStream is=new CharacterInputStreamDecorate(new BufferedInputStream(new FileInputStream(new File(CharacterInputStreamDecorateTest.class.getResource(pathname).getFile()))));
    			while ((c=is.read())>=0) {
    				System.out.print((char)c);
    			}
    		} catch (Exception e) {
    			// TODO: handle exception
    			e.printStackTrace();
    		}
    	}
    
    }
    
    测试数据:

    what's you want from learn design pattern?
    may be,it is something...

    结果:

    WHAT'S YOU WANT FROM LEARN DESIGN PATTERN?
    MAY BE,IT IS SOMETHING...



    2、简单工厂、工厂方法模式、抽象工厂模式

    /**
     * 设计原则:
     * 		依赖倒置原则:依赖于抽象,而非具体实现
     * 
     * 所有的工厂都是用于封装对象的创建
     * 用于将客户程序与具体应用解耦
     * 
     * 简单工厂:在一个类中处理创建对象的细节
     * 
     * 工厂方法模式:
     *   让子类决定初始化什么样的对象,即将类的实例化推迟到子类中进行
     * 工厂方法使用继承,将对象的创建委托给子类进行创建  
     *   
     * 抽象工厂模式:
     *   定义了一个接口,提供了创建依赖对象的家族,但是不指定具体创建什么类型  
     * 抽象工厂使用组合概念,构建对象的家族 
     * 
     * 
     * 实例:
     * 披萨店的加盟模式
     *    披萨店可以有很多加盟店
     *     不同的加盟店做的披萨可以口味不同 但是制作披萨的流程与原料都必须是一致的
     * @author Administrator
     *
     */

    先来看看最简单的简单工厂

    package com.undergrowth.factory;
    
    /**
     * 设计原则:
     * 		依赖倒置原则:依赖于抽象,而非具体实现
     * 
     * 所有的工厂都是用于封装对象的创建
     * 用于将客户程序与具体应用解耦
     * 
     * 简单工厂:在一个类中处理创建对象的细节
     * 
     * 工厂方法模式:
     *   让子类决定初始化什么样的对象,即将类的实例化推迟到子类中进行
     * 工厂方法使用继承,将对象的创建委托给子类进行创建  
     *   
     * 抽象工厂模式:
     *   定义了一个接口,提供了创建依赖对象的家族,但是不指定具体创建什么类型  
     * 抽象工厂使用组合概念,构建对象的家族 
     * 
     * 
     * 实例:
     * 披萨店的加盟模式
     *    披萨店可以有很多加盟店
     *     不同的加盟店做的披萨可以口味不同 但是制作披萨的流程与原料都必须是一致的
     * @author Administrator
     *
     */
    
    public  class PizzaStore {
    	
    	/**
    	 * 定披萨
    	 */
    	public void orderPizza(String type){
    		
    		//简单工厂方式让我们还是依赖 于一个特定的实现  我们需要依赖于抽象
    		Pizza pizza=PizzaSimpleFactory.createPizza(type);
    		
    		//Pizza pizza=createPizza(type);
    		//保证制作披萨的流程一致
    		pizza.prepare();
    		pizza.bake();
    		pizza.cut();
    		pizza.box();
    	}
    	/**
    	 * 使用工厂方法模式  将对象的创建推迟到子类中
    	 * @return
    	 */
    	//public abstract Pizza createPizza(String type);
    	
    }
    


    将对象的创建放置在一个类中

    package com.undergrowth.factory;
    
    
    /**
     * 简单工厂 创建披萨
     * @author Administrator
     *
     */
    public class PizzaSimpleFactory {
    	
    	public static Pizza createPizza(String type){
    		Pizza pizza=null;
    		switch (type) {
    		case "NYCheese":
    			pizza=new NYCheesePizza();
    			break;
    		default:
    			pizza=new CaliforniaCheesePizza();
    			break;
    		}
    		return pizza;
    	}
    	
    }
    


    但是简单工厂让让我们的代码  还是依赖与实现 而非抽象 为了达到这一原则  使用工厂方法模式  让子类负责创建对象 让对象的创建与逻辑代码解耦

    修改披萨工厂类 如下

    package com.undergrowth.factory;
    
    /**
     * 设计原则:
     * 		依赖倒置原则:依赖于抽象,而非具体实现
     * 
     * 所有的工厂都是用于封装对象的创建
     * 用于将客户程序与具体应用解耦
     * 
     * 简单工厂:在一个类中处理创建对象的细节
     * 
     * 工厂方法模式:
     *   让子类决定初始化什么样的对象,即将类的实例化推迟到子类中进行
     * 工厂方法使用继承,将对象的创建委托给子类进行创建  
     *   
     * 抽象工厂模式:
     *   定义了一个接口,提供了创建依赖对象的家族,但是不指定具体创建什么类型  
     * 抽象工厂使用组合概念,构建对象的家族 
     * 
     * 
     * 实例:
     * 披萨店的加盟模式
     *    披萨店可以有很多加盟店
     *     不同的加盟店做的披萨可以口味不同 但是制作披萨的流程与原料都必须是一致的
     * @author Administrator
     *
     */
    
    public abstract class PizzaStore {
    	
    	/**
    	 * 定披萨
    	 */
    	public void orderPizza(String type){
    		
    		//简单工厂方式让我们还是依赖 于一个特定的实现  我们需要依赖于抽象
    		//Pizza pizza=PizzaSimpleFactory.createPizza(type);
    		
    		Pizza pizza=createPizza(type);
    		//保证制作披萨的流程一致
    		pizza.prepare();
    		pizza.bake();
    		pizza.cut();
    		pizza.box();
    	}
    	/**
    	 * 使用工厂方法模式  将对象的创建推迟到子类中
    	 * @return
    	 */
    	public abstract Pizza createPizza(String type);
    	
    }
    


    纽约的披萨工厂

    package com.undergrowth.factory;
    
    public class NYPizzaStore extends PizzaStore {
    
    	@Override
    	public Pizza createPizza(String type) {
    		// TODO Auto-generated method stub
    		Pizza pizza=null;
    		if("Cheese".equals(type))
    			pizza=new NYCheesePizza();
    		else if("Clam".equals(type)){
    			pizza=new NYClamPizza();
    		}
    		return pizza;
    	}
    
    }
    

    哈喇披萨

    package com.undergrowth.factory;
    
    /**
     * 纽约披萨
     * @author Administrator
     *
     */
    public class NYClamPizza extends Pizza {
    	public NYClamPizza(){
    		setName(NYClamPizza.class.getSimpleName());
    	}
    
    	@Override
    	public void prepare() {
    		// TODO Auto-generated method stub
    		System.out.println(NYClamPizza.class.getSimpleName()+"	准备做披萨...");
    	}
    }
    



    测试类

    package com.undergrowth.factory;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    public class PizzaStoreTest {
    
    	@Test
    	public void test() {
    		PizzaStore ps=null;
    		//简单工厂测试
    		/*ps=new PizzaStore();
    		ps.orderPizza("NYCheese");*/
    		
    		//工厂方法模式
    		ps=new NYPizzaStore();
    		ps.orderPizza("Clam");
    		
    		//抽象工厂模式
    	    //创建披萨的原料从抽象工厂中获取
    		/*ps=new NYPizzaStore();
    		ps.orderPizza("Cheese");*/
    	}
    
    }
    

    结果

    NYClamPizza	准备做披萨...
    NYClamPizza	对披萨进行烘烤
    NYClamPizza	对披萨进行切片
    NYClamPizza	对披萨进行装盒
    



    当我为了确保原料一致时,我做披萨产生的原料都从原料工厂取 这样就能保证披萨的原料是一致的了  使用抽象工厂解决此问题

    皮萨类

    package com.undergrowth.factory;
    
    /**
     * 披萨 用于构建披萨
     * @author Administrator
     *
     */
    public  abstract class Pizza {
    	private String name;
    	 Dough dough;
    	 Cheese cheese;
    	 Clam clam;
    	/**
    	 * 构建披萨的原料从抽象工厂中获取
    	 */
    	public abstract void prepare();
    	public void bake(){
    		System.out.println(getName()+"	"+"对披萨进行烘烤");
    	}
    	public void cut(){
    		System.out.println(getName()+"	"+"对披萨进行切片");
    	}
    	public void box(){
    		System.out.println(getName()+"	"+"对披萨进行装盒");
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	
    	
    }
    

    纽约奶酪披萨

    package com.undergrowth.factory;
    
    /**
     * 纽约披萨
     * @author Administrator
     *
     */
    public class NYCheesePizza extends Pizza {
    	
    	IngredientFactory ingredientFactory=new NYIngredientFactory();
    	public NYCheesePizza(){
    		setName(NYCheesePizza.class.getSimpleName());
    	}
    	
    
    	@Override
    	public void prepare() {
    		// TODO Auto-generated method stub
    		System.out.println("开始准备做披萨");
    		System.out.println("面粉:"+ingredientFactory.createDough());
    		System.out.println("奶酪:"+ingredientFactory.createCheese());
    		System.out.println("哈喇:"+ingredientFactory.createClam());
    	}
    }
    


    原料工厂

    package com.undergrowth.factory;
    
    public interface IngredientFactory {
    	public Dough createDough();
    	public Clam createClam();
    	public Cheese createCheese();
    }
    

    纽约原料工厂

    package com.undergrowth.factory;
    
    public class NYIngredientFactory implements IngredientFactory {
    
    	@Override
    	public Dough createDough() {
    		// TODO Auto-generated method stub
    		return new ThinDough();
    	}
    
    	@Override
    	public Clam createClam() {
    		// TODO Auto-generated method stub
    		return new FreshClam();
    	}
    
    	@Override
    	public Cheese createCheese() {
    		// TODO Auto-generated method stub
    		return new SweetCheese();
    	}
    
    }
    
    相关的原料接口与实现类

    package com.undergrowth.factory;
    
    public interface Dough {
    	
    }
    
    package com.undergrowth.factory;
    
    public class ThinDough implements Dough {
    
    	@Override
    	public String toString() {
    		return "ThinDough [toString()=" + super.toString() + "]";
    	}
    	
    }
    

    package com.undergrowth.factory;
    
    public interface Clam {
    
    }
    

    package com.undergrowth.factory;
    
    public class FreshClam implements Clam {
    
    	@Override
    	public String toString() {
    		return "FreshClam [toString()=" + super.toString() + "]";
    	}
    	
    }
    


    package com.undergrowth.factory;
    
    public interface Cheese {
    
    }
    

    package com.undergrowth.factory;
    
    public class SweetCheese implements Cheese {
    
    	@Override
    	public String toString() {
    		return "SweetCheese [toString()=" + super.toString() + "]";
    	}
    	
    }
    

    测试类

    package com.undergrowth.factory;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    public class PizzaStoreTest {
    
    	@Test
    	public void test() {
    		PizzaStore ps=null;
    		//简单工厂测试
    		/*ps=new PizzaStore();
    		ps.orderPizza("NYCheese");*/
    		
    		//工厂方法模式
    		/*ps=new NYPizzaStore();
    		ps.orderPizza("Clam");*/
    		
    		//抽象工厂模式
    	    //创建披萨的原料从抽象工厂中获取
    		ps=new NYPizzaStore();
    		ps.orderPizza("Cheese");
    	}
    
    }
    

    结果

    开始准备做披萨
    面粉:ThinDough [toString()=com.undergrowth.factory.ThinDough@1e064c]
    奶酪:SweetCheese [toString()=com.undergrowth.factory.SweetCheese@328c40]
    哈喇:FreshClam [toString()=com.undergrowth.factory.FreshClam@3cfaab]
    NYCheesePizza	对披萨进行烘烤
    NYCheesePizza	对披萨进行切片
    NYCheesePizza	对披萨进行装盒
    


    上面即使简单工厂 工厂方法  抽象工厂的简单实现

         简单工厂----使用简单,但使逻辑代码依赖于具体实现

       工厂方法---时逻辑代码依赖于抽象,让子类负责对象的创建

      抽象工厂----加强版的工厂方法,可用于创建依赖对象的家族



    记录学习的脚步

  • 相关阅读:
    数据库事务的四个隔离级别浅析
    Spring事务管理之几种方式实现事务
    SQL调优简介及调优方式
    Spring MVC工作流程图
    java中的垃圾回收机
    iOS 本地化-国际化-(App名字国际化)
    iOS-自建iPa应用分发平台
    稳定App缓存
    iOS-保存图片到(自定义)相册步骤
    iOS -根据网络状态加载图片
  • 原文地址:https://www.cnblogs.com/liangxinzhi/p/4275545.html
Copyright © 2011-2022 走看看