文章目录
ch7 外观模式
0. 序
-
外观与适配器是不同的模式
-
装饰者模式?适配器模式?
装饰着模式是把对象包装起来,赋予新的职责。
适配器模式是对现有对象进行包装,让它的接口看起来像是别的东西。这可以把类的接口转换成想要的接口。
-
适配器模式 --适配器 应用
这样只需要去添加适配器的代码了。不需要改变原有的代码(设计原则)
现实中的例子:插头与转换头。
适配器定义:将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间。
这一部分的内容比较容易理解,以下仅附上练习代码。
1. 适配器Exercise Code
/**
* 鸭子接口
* @author chain
*/
public interface Duck {
/**
* 叫
*/
void quack();
/**
* 飞行方法
*/
void fly();
}
/**
* @author chain
* @date 2020/4/9
* @description 火鸡的基类
*/
public interface Turkey {
/**
* 火鸡的咕咕叫方法
* @author chain
* @date 2020/4/9
* @description
*/
void gobble();
/**
* 火鸡的飞行方法
* @author chain
* @date 2020/4/9
*
*/
void fly();
}
/**
* @author chain
* @description 火鸡实现类
* @date 2020/4/9
*/
public class WildTurkey implements Turkey {
@Override
public void gobble() {
System.out.println("火鸡 叫 gobble");
}
@Override
public void fly() {
System.out.println("火鸡 飞");
}
}
我需要做的: 把一只火鸡 包装成一只鸭子 。 很显然,火鸡与鸭子接口不同,不能直接拿来用,那么就增加一个适配器,该适配器接受火鸡,输出鸭子!
/**
* @author chain
* @description 适配器类 Turkey --> Duck
* @date 2020/4/9
*/
public class TurkeyAdapter implements Duck {
/**
* 接受的火鸡 需要转换的接口
*/
Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
@Override
public void quack() {
//把火鸡的叫方法伪装成鸭子叫方法
turkey.gobble();
}
@Override
public void fly() {
turkey.fly();
}
public static void main(String[] args) {
//测试代码
Turkey wildTurkey=new WildTurkey();
//这里已经把一只火鸡伪装成鸭子
Duck turkeyAdatpter = new TurkeyAdapter(wildTurkey);
turkeyAdatpter.fly();
}
}
很显然,适配器模式就是在外面套了一层接口,里面对应的方法的实现仍然是被包装的对象的方法
2. 外观模式
装饰者模式:不改变接口,但假如责任
适配器模式:将一个接口转换成另一个接口
外观模式:让接口更简单
外观模式更像是把许多复杂的接口经过包装,变成一个简单的接口。p262实例:在看电影前,要打开电视,设置dvd, 设置灯光等一系列操作,这些都是子系统的功能;采用外观模式,将上述子系统功能封装成一个新的接口,那么直接一键就可以调用上述子系统(组合的方式)功能。
**外观模式:**提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
**新的OO原则:**最少知识原则:减少对象之间的交互,只留下几个"密友"---->不要让太多类耦合
ch8 模板方法模式–封装算法
0. 序
这个模式有点类似于 把变化的代码抽离封装,但是 这个模式是给变化的方法定义了一个骨架,并且将该骨架的实现延迟到子类中。这个模式就是来创建一个算法的模板,其中任何步骤都可以是抽象的,抽象部分将由子类实现,可以确保算法的数据结构保持不变。
package 模块封装模式;
/**
* @author chain
* @description
* @date 2020/4/11
*/
public abstract class AbstarctClass1 {
/**
* 封装代码模板 且为final 防止子类修改这个算法模板
* @author chain
* @date 2020/4/11
*/
final void templateMethod(){
primitiveOperation1();
primitiveOperation2();
concreteOperation();
hook();
}
/**
* 操作1 由子类实现
* @author chain
* @date 2020/4/11
*/
abstract void primitiveOperation1();
/**
* 操作2 由子类实现
* @author chain
* @date 2020/4/11
*/
abstract void primitiveOperation2();
/**
* 子类的共同的代码
* @author chain
* @date 2020/4/11
*/
void concreteOperation(){
//省略实现代码
}
void hook(){
//什么都不做 由子类去覆盖
//这个好处可以让子类去向模板方法添加新的方法
}
}
策略模式和模板模式都封装算法,策略使用组合,模板使用继承,工厂方法是模板方法的一种特殊版本。
ch9 迭代器与组合
0. 序
迭代器 --Java中的Iterator 可以在不用了解集合内部实现的情况下,遍历集合
其他:略
ch10 状态模式
0. 序
策略模式围绕可以互换的算法来创建成功业务。状态模式通过改变对象内部的状态来帮助对象控制自己的行为。
对于书上的糖果机的例子,在不加入“赢家模式”的时候代码是很简单易懂的,就是对于糖果机的几种状态,每次操作都去根据当前的状态做if-else操作即可。加入“赢家模式”后,显然如果要对之前的代码进行维护,修改的成本是很大的。因此,摆脱旧的条件代码,将动作委托到状态类上(封装变化),让状态来实现自己的行为。
对于状态抽象出一个接口State
, 实现有SoldState, SoldOutState, NoQuarterState, HasQuarterState, WinnerState
,实现的子类各自去实现自己在状态下的操作方法即可。
实际上,我们对状态进行改变的话,糖果机的行为会因为状态的改变而改变。每一个状态又是独立的,方便维护与扩展
2. Code
状态模式的一些代码
状态基类
package 状态模式;
/**
* 状态接口
*
* @author chain
* @date 2020/4/12
*/
public interface State {
/**
* 插入
*
* @author chain
* @date 2020/4/12
*/
void insertQuarter();
/**
* 退钱
*
* @author chain
* @date 2020/4/12
*/
void ejectQuarter();
/**
* 转动把手
* @author chain
* @date 2020/4/12
*/
void turnCrank();
/**
* 售完
* @author chain
* @date 2020/4/12
*/
void dispense();
}
状态实现类(只列出一种)
package 状态模式;
import java.util.Random;
/**
* @author chain
* @description 未投钱状态
* @date 2020/4/12
*/
public class HasQuarterState implements State {
Random randomWinner=new Random(System.currentTimeMillis());
GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("you has inserted a quarter");
}
@Override
public void ejectQuarter()
{
gumballMachine.setState(gumballMachine.getNoQuarterState());
System.out.println("you haven't inserted a quarter ");
}
@Override
public void turnCrank() {
System.out.println("you turned...");
int winner=randomWinner.nextInt(10);
if (winner==0&&gumballMachine.getCount()>1){
gumballMachine.setState(gumballMachine.getWinnerState());
}else {
gumballMachine.setState(gumballMachine.getSoldState());
}
}
@Override
public void dispense() {
System.out.println("no gumball dispensed");
}
}
机器类,状态组合
package 状态模式;
/**
* @author chain
* @description
* @date 2020/4/12
*/
public class GumballMachine {
private State soldOutState;
private State noQuarterState;
private State hasQuarterState;
private State soldState;
public State getWinnerState() {
return winnerState;
}
/**
* 十次抽中一次的赢家状态
*/
private State winnerState;
/**
* 初始状态 为soldOutState
* state为糖果机的状态
*/
private State state=soldOutState;
int count=0;
public GumballMachine(int numberGumballs){
soldOutState=new SoldOutState(this);
noQuarterState=new NoQuarterState(this);
hasQuarterState=new HasQuarterState(this);
soldState=new SoldState(this);
winnerState=new WinnerState(this);
this.count=numberGumballs;
if (numberGumballs>0){
state=noQuarterState;
}
}
public void insertQuarter(){
state.insertQuarter();
}
public void ejectQuarter(){
state.ejectQuarter();
}
public void turnCrank(){
state.turnCrank();
state.dispense();
}
public void setState(State state) {
this.state = state;
}
void releaseBall(){
System.out.println("a gumball comes rolling out the slot...");
if (count!=0){
count--;
}
}
//其他方法
// getter setter toString
public static void main(String[] args) {
GumballMachine gumballMachine=new GumballMachine(5);
System.out.println("糖果机构造完成: "+ gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("当前糖果机:"+gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("当前糖果机:"+gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.print(gumballMachine);
}
}
通过这些代码,很容易观察出 不使用状态模式的缺点,在大量的if - else 情况下修改很大,没有弹性。使用状态模式,将每一个状态的动作交给该状态去完成,修改只关心状态本身的功能的实现,而机器Machine只是组合一下状态并根据状态的转换来实现动作变化。