装饰模式: 动态的为对象添加附加功能,提供了一种扩展机制,比继承更具有扩展性
简单工厂:在一个类中处理创建对象的细节
工厂方法模式:
* 让子类决定初始化什么样的对象,即将类的实例化推迟到子类中进行
* 工厂方法使用继承,将对象的创建委托给子类进行创建
抽象工厂模式:
* 定义了一个接口,提供了创建依赖对象的家族,但是不指定具体创建什么类型
* 抽象工厂使用组合概念,构建对象的家族
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 对披萨进行装盒
上面即使简单工厂 工厂方法 抽象工厂的简单实现
简单工厂----使用简单,但使逻辑代码依赖于具体实现
工厂方法---时逻辑代码依赖于抽象,让子类负责对象的创建
抽象工厂----加强版的工厂方法,可用于创建依赖对象的家族
记录学习的脚步