设计模式之装饰模式、工厂方法模式、抽象工厂模式浅析
装饰模式: 动态的为对象添加附加功能,提供了一种扩展机制,比继承更具有扩展性
简单工厂:在一个类中处理创建对象的细节
工厂方法模式: * 让子类决定初始化什么样的对象,即将类的实例化推迟到子类中进行 * 工厂方法使用继承,将对象的创建委托给子类进行创建
抽象工厂模式: * 定义了一个接口,提供了创建依赖对象的家族,但是不指定具体创建什么类型 * 抽象工厂使用组合概念,构建对象的家族
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) 编辑 收藏 举报