设计模式入门(策略模式)
设计原则1:找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
设计原则2:针对接口编程,而不是针对实现变成。
设计原则3:多用组合,少用继承
理解:针对实现变成
Dog d = new Dog();//一个animal超类的具体实现,代码写后不好更改
d.bark();
针对接口编程
Animal animal = new Dog();
animal.makeSound();
利用animal类进行调用。
或者根据运行时的参数实现具体的对象(比如参数改变就生成不同的具体类,但程序不用有多余动作,可直接调用接口)
a = getAnimal();
a.makeSound();
而且该接口是又其他的类实现的,animal类不关注该类如何实现。
场景代码:只演示duck类,重点是理解接口和行为的区别
public abstract class Duck{
FlyBehavior quackBehavior;//一个行为接口类型声明
QuackBehavior quackBehavior;
public Duck(){
}
public abstract void display();
public void performFly(){
flyBehavior.fly();//委托给行为类
}
...
}
接口与行为的实现
public interface FlyBehavior{
public void fly();
}
//一个具体的实现相当于一个”算法“
public class FlyWithWings implements FlyBehavior{
public void fly(){
system.out.println("I'm flying");
}
}
//一个具体的duck类
public class MallardDuck extends Duck{
public MallardDuck(){
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}//定义接口代表的具体类
...
}
调用方式:
public class MiniDuckSimulator{
public static void main(String[] args){
Duck mallard = new MallardDuck();
mallard.performFly();
}
}
鸭子的行为不是继承来的,而是和适当的行为对象”组合“来的。
策略模式:
定义了算法族,分别封装起来,让他们之间可以互相替换。此模式让算法的变化(飞行类的实现)独立于使用算法的客户(一个使用飞行类的鸭子)。
重要:
继承(extends) 实线空心箭头
实现(implement)虚线空心箭头
”有一个“(组合)实线普通箭头
观察者模式
定义: 定义对象之间一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。
JAVA中,观察者是一个接口,具有update的方法,将接口的实现类add进主题,主题在更新数据时会调用观察者的update接口,该接口被调用后,观察者可以行使其他方法。
c++中,可以理解为传入一个_msgFunc地址,主题更新后调用该地址实现方法。
工厂模式
工厂方法
abstract product factortMethod (String type)
工厂方法可能需要参数来指定所要的产品
工厂方法是抽象的,所以依赖子类来处理对象的创建
工厂方法必须返回一个产品
工厂方法将客户(超类中的代码 orderizza())和实际创建具体代码分隔开来
定义:定义一个创建对象的接口,但由子类决定要实例化的类型是哪一个,工厂方法让类把实例化推迟到子类。
疑问:什么是实例化? 就是new一个对象
依赖倒置原则:
要依赖抽象,而不要依赖具体类。
理解:
一个PizzaStore 是高层组件 一个比萨实现是底层组件,依赖pizza抽象。但具体的pizza实现,要依赖于高层pizzastore,由pizzastore决定实现,这就是依赖倒置。
抽象工厂可理解为提供抽象的工厂接口,由具体的各个工厂模式实现。
工厂方法多使用继承,抽象工厂使用组合(多个工厂的组合)
工厂方法的核心:通过子类创建对象。将客户从具体类型中解耦。
命令模式
将”发出请求的对象“与”接受与执行请求的对象“分隔开来。遥控器下订单,调用对象的orderUp(),实现功能。
线程池循环执行类似于命令模式。上层专注于定时器,不关心命令后具体调用。
定义:将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象,命令模式也支持可撤销的操作。
实现一个命令接口
public interface Command{
public void execute();
}
实现一个命令
public class LightOnCommand implements Command{
Light light;
public LightOnCommand (Light light){//用构造
this.light = light;
}
public void execute(){
light.on();
}
}
public class SimpleRemoteControl{
Command slot;
public SimpleRemoteControl(){}
public void setCommand (Command command){
slot = command;
}
public void buttonWasPressed(){
slot.excute();
}
}
//命令的传递
public class RemoteControlTest{
public static void main(String[] args){
SimpleRemoteControl remote = new SimpleRemoteControl();
Light light = new Light();
LightOnCommand lightOn = new LightOnCommand(light);
remote.setCommand(lightOn);
remote.buttonWasPressed();
}
适配器模式
定义:将一个类的接口,转换成客户期望的另一个接口。
设计原则:“最少知识”原则,较少对象之间的交互。当你正在设计一个系统,不管是任何对象,都要注意它所交互的类有哪些,并注意它和这些类是如何交互的。
模板方法
定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。
public abstract class CaffeineBeverage{
void final prepareRecipe(){
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater(){
//实现
}
void pourInCap(){
//实现
}
}
钩子
在模板类上提供一个条件语句,并提供一个默认的方法,如果子类不复写方法,则使用模板提供的默认方法
if(costomerWantsCondiments()){
addCondiments();
}
boolean costomerWantsCondiments(){
return true;
}
钩子是一种方法,它在抽象类中不做事,或者只做默认的事,子类可以选择要不要覆盖它。
策略模式和模板方法模式都算封装算法,一个用组合,一个用继承。
工厂方法是模板方法的一个特殊版本。
迭代器与组合模式
设计原则:一个类应该只有一个引起变化的原因。
理解:当我们允许一个类不但要完成自己的事情(管理某种聚合),还要担负更多的责任(例如遍历)等,就给了这个类两个变化的原因。
例如NodeMgr和Node分开//N+0用的是组合模式
区分设计中的责任是难点。
组合模式定义:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
N+0的状态模式
状态模式
策略模式是围绕可以互换的算法来创建业务,状态模式通过改变对象内部的状态来帮助对象控制自己的行为。
定义:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。