设计模式之装饰模式、工厂方法模式、抽象工厂模式浅析

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

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

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

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


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()+"\t"+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()+"\t"+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()+"\t价格:"+baverage.cost());
	    
		//一份摩卡 一份蜂蜜的茶叶
		baverage=new Tea();
		baverage=new MochaIngredient(baverage);
		baverage=new HoneyIngredient(baverage);
		System.out.println(baverage.getDescription()+"\t价格:"+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()+"\t准备做披萨...");
	}
}



测试类

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()+"\t"+"对披萨进行烘烤");
	}
	public void cut(){
		System.out.println(getName()+"\t"+"对披萨进行切片");
	}
	public void box(){
		System.out.println(getName()+"\t"+"对披萨进行装盒");
	}
	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	对披萨进行装盒


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

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

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

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



记录学习的脚步

posted on 2014-12-01 21:57  liangxinzhi  阅读(196)  评论(0编辑  收藏  举报