设计模式学习
面向对象设计原则:
1.单一职责
一个类的功能单一,不该做的不做
2.开放-封闭
对于完成的类,尽量不要修改,如果有需求,可以扩展。对于修改关闭,对于扩展开放
3.依赖到转
细节依赖于抽象,抽象不依赖细节。为了高内聚,低耦合(面向接口编程)
4.里氏替换
子类可以完全替换父类使用。
5.迪米特法则
如果两个类需要直接交互,就通过第三者来进行交互。低耦合
工厂模式Factory:
用于对象封装。需要一个抽象工厂,当用户有需要东西,只需把特征(区别点)告诉工厂,工厂就创建相应的东西。
public class BmwX5Car extends Car {public BmwX5Car() {}}public class BmwX7Car extends Car {public BmwX7Car() {}}public class SimpleCarFactory {// 简单工厂public Car createCar(String type) {if ("bmwx5".equals(type)) {return new BmwX5Car();} else if ("bmwx7".equals(type)) {return new BmwX7Car();} elsereturn null;}}工厂方法模式Factory Method:
用于对象封装。需要一个抽象工厂接口,然后定义不同的工厂创建对象。与工厂的区别在于,对创建什么对象的决策是否透明(对于客户,知道创建什么对象)。
抽象工厂模式:
对于工厂方法的高度抽象,不仅对工厂进行接口抽象,对工厂生产的东西也进行接口抽象。
策略模式Strategy:
类似于工厂模式,用于对行为,算法封装。需要根据特征(区别点)调用相应的实现方法。
定义一个抽象类,其中算法不同的方法由子类实现。
public interface Strategy {boolean isPrime();}public class Miller implements Strategy {public boolean isPrime() {boolean result = false;System.out.println("这里是用来写Miller策略获取结果!");return result;}}public class Fermat implements Strategy {public boolean isPrime() {boolean result = false;System.out.println("这里是用来写Fermat策略获取结果!");return result;}}public class Primality {private Strategy strategy; // 私有的接口public Primality(Strategy s) {strategy = s;}public boolean run(int n) {return strategy.isPrime();}}public class TestStrategy {public static void main(String[] args) {Primality prime = null;int n = 1;Character ch = 'm';switch (ch) {case 'l':case 'L':prime = new Primality(new Miller());break;case 'm':case 'M':prime = new Primality(new Fermat());break;}}}装饰模式Decorator:
实现子类之间的方法的相互调用,也可以说是子类通过别的子类进行功能扩展。具体实现是通过在子类中通过父类的对象,显式的调用子类所继承的父类方法。然后在使用时,通过一个子类初始化另一个子类,这个过程就叫做装饰。
例子地址:http://apps.hi.baidu.com/share/detail/2044628
public abstract class Car { String name = "Unknow Car"; public String getName() { return this.name; } public abstract float cost(); } // 标准型 BMW 汽车 public class BmwCar extends Car { public BmwCar() { this.name = "BMW"; } @Override public float cost() { return 50 * 10000.00f; } } // 标准 QQ 汽车 public class QQCar extends Car { public QQCar() { this.name = "QQ"; } @Override public float cost() { return 3 * 10000.00f; } } // 配件装饰者 public abstract class AccesoryDecorator extends Car { public abstract String getName(); } // 安全气囊配件 public class AirbagAccesory extends AccesoryDecorator { private Car car; public AirbagAccesory(Car car) { this.car = car; } @Override public String getName() { return car.getName() + ",Airbag"; } @Override public float cost() { return car.cost() + 1500; } } // 摄像头配件 public class CameraAccesory extends AccesoryDecorator { private Car car; public CameraAccesory(Car car) { this.car = car; } @Override public String getName() { return car.getName() + ",Camera"; } @Override public float cost() { return car.cost() + 800; } } // 测试程序 public static void main(String[] args) { Car car1 = new AirbagAccesory(new CameraAccesory(new QQCar())); printCarInfo(car1); Car car2 = new AirbagAccesory(new CameraAccesory(new BmwCar())); printCarInfo(car2); } public static void printCarInfo(Car car) { System.out.println("Car Name:" + car.getName() + ",Cost:"+ car.cost()); }代理模式Proxy:
这个模式就是两个实现相同接口的类,一个是具体的实现类(真实类),从中访问外部数据,另一个是通过实现类的方法访问外部对象(代理类)。但是应用只能够知道代理类,不知到实现类。代理模式在web应用常见。
外观模式(门面模式)Facade:
这个模式和代理模式类似,都是对行为进行屏蔽(实现细节),为子系统中的各个接口的操作提供一个供外部调用的通用的接口。与代理模式不同的是,代理模式的代理类和实现类出于同一接口,外观是通过通用接口将各个接口进行了组合。
// 电源 public class Power { public void connect() { System.out.println("The power is connected."); } public void disconnect() { System.out.println("The power is disconnected."); } } // 主板 public class MainBoard { public void on() { System.out.println("The mainboard is on."); } public void off() { System.out.println("The mainboard is off."); } } // 计算机外观 public class Computer { private Power power; private MainBoard board; public Computer(Power power, MainBoard board) { this.power = power; this.board = board; } public void startup() { this.power.connect(); this.board.on(); } public void shutdown() { this.board.off(); this.power.disconnect(); } }中介者模式():
类似与门面模式,门面模式是介于客户程序与子系统之间的,而中介者模式是介于子系统与子系统之间的。
原型模式Prototype:
通过初始化一个对象(必须实现object的clone方法),通过clone的方法生成其他的对象进行使用。clone属于浅拷贝,copy属于深拷贝,浅拷贝是引用传递,深拷贝是值传递。所以,对于普通类型的数据,通过clone后,可以按照要求进行修改,不会影响原始对象的值,但是对于引用类型的数据,修改后会影响原始对象。
模板方法模式Template:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。将一些共同的方法或执行步骤抽象到父类中,不同的部分通过接口(抽象方法)让子类实现。子类就可以做到不改变算法的结构就可以做到自定义算法的某些特定细节。
// 导游public abstract class Guide {public final void leadTour() {this.buyTickets();if (needRest()) {// 钩子this.bookingHotel();}this.visit();this.getBack();}// 购买旅行票public abstract void buyTickets();// 预定旅店public abstract void bookingHotel();// 参观public void visit() {System.out.println("Visit the scenic spot.");}// 返回public abstract void getBack();// 是否需要住宿public boolean needRest() {return true;}}public class BeiJingGuide extends Guide {@Overridepublic void buyTickets() {System.out.println("Buy bus tickets.");}@Overridepublic void bookingHotel() {// 因为不需要住宿,所以这里什么都不做}@Overridepublic void getBack() {System.out.println("Get back by bus.");}// 覆盖钩子,取消住宿@Overridepublic boolean needRest() {return false;}}public class HaiNanGuide extends Guide {@Overridepublic void buyTickets() {System.out.println("Buy plane tickets.");}@Overridepublic void bookingHotel() {System.out.println("Booking HaiNan Hotel.");}@Overridepublic void getBack() {System.out.println("Get back by air.");}}建造者模式(生成器模式)Builder:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。该模式与模板方法模式非常相似,只是比模板方法模式多了一个指挥类,该类用于固定构建过程,相当于模板中的固定算法骨架的功能。
观察者模式Observer:
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听同一个主体对象(被观察者),如果主体对象在状态改变时,会通知所有的观察者,以便更新自己。观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来。最好是通过抽象类(接口)进行相互关联。
主要解决一(主题subject)对多(observer)的问题,如果主题变,就要通知所有的observer。实现,subject定义observer的容器变量和关联因子,如果关联因子变化,就要执行容器中每一个observer的update方法。
// 博客public interface Subject {public void addObserver(Observer observer);public void removeObserver(Observer observer);public void notifyObservers();}interface Observer {public void update(String blog);}class Blogger implements Subject {private List<Observer> observers;private String blog;public Blogger() {observers = new ArrayList<Observer>();}public void addObserver(Observer observer) {observers.add(observer);}public void removeObserver(Observer observer) {observers.remove(observer);}public void notifyObservers() {for (Observer o : observers) {o.update(blog);}}// 发表新博客文章public void writeNewBlog(String blog) {this.blog = blog;notifyObservers();}}// 邮件订阅者public class EmailSubscriber implements Observer {public void update(String blog) {// 发送电子邮件}}// RSS 订阅者public class RssSubscriber implements Observer {public void update(String email) {// 更新 RSS 信息}}状态模式State:
状态模式用于消除大量的分支判断。把状态的逻辑判断转移到表示不同状态的一系列类中,就可以把复杂的判断简单化。定义n个状态类(继承一个父类),在每一个状态类中有两种可能,一是自己处理,二是传给下一状态类处理。
public abstract class State{int type;public void setType(int t){type = t;} public abstract void doSomething();}public class Angry extends State{public void doSomething(){if(type > 0){System.out.println("I'm angry!");} else {new Happy().doSomething();} }}public class Happy extends State{ public void doSomething(){if(type < 0){System.out.println("I'm happy!");} else {new Angry().doSomething();} }}public static void main(String[] ss){State happy = new Happy();happy.setType(-1);happy.doSomething();}职责连模式(Chain of responsibility):
和状态模式类似,是对请求处理类的封装。状态模式一般适用与if else ,职责连适用与switch,状态模式的下一步处理对象是由内部(编译)决定的,但是职责连的下一步处理对象是由客户端决定的。
适配器模式(Adapter):
将一个客户无法使用的东西(源),通过中间件(适配器)转换为可以使用的东西(目标)。当然,适配器需要继承目标。适用与功能都实现了,但是由于接口无法不同导致无法使用,此时中间插入一个转换层做适配,就可以解决。
备忘录模式(Memento):
在不破坏封装的前提下,捕获一个对象的状态,并且在对象之外保存,以便随时恢复。适用于需要维护历史数据的情况。需要定义一个备忘类(状态bean),管理类(备忘类bean)。客户端通过管理类,可以保存或恢复状态。
组合模式(Composite):
将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式对单个对象的使用和组合对象的使用具有一致性。抽象构件类(Component),叶子构件类(leaf),树枝构件类(Composite),客户类(Client)。客户通过对接口(component)的使用,将一个个构建(leaf,composite)组合起来。
public interface IMenu {// 取得名称public String getName();// 显示public void display();// 添加菜单public void addItem(IMenu menu);}public class Menu implements IMenu {private List<IMenu> items = new ArrayList<IMenu>();private String name;public Menu(String name) {this.name = name;}public void addItem(IMenu menu) {items.add(menu);}public void display() {System.out.println(this.name + ":Menu");for (IMenu menu : items) {menu.display();}}public String getName() {return this.name;}}public class MenuItem implements IMenu {private String name;public MenuItem(String name) {this.name = name;}public void display() {System.out.println(this.name + ":MenuItem");}public String getName() {return this.name;}public void addItem(IMenu menu) {throw new UnsupportedOperationException();}}public class MenuBar {private List<IMenu> menus = new ArrayList<IMenu>();public void addMenu(IMenu menu) {this.menus.add(menu);}public void display() {System.out.println(":MenuBar");for (IMenu menu : menus) {menu.display();}}}迭代器模式(Iterator pattern):
提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。一般封装3个方法next(),hasNext(),remove();该模式应该可以废弃,因为现在语言已经集成了该模式。
单例模式(Singleton):
保证一个类只有一个实例,且提供一个访问它的访问点,饿汉式(提前创建好对象),懒汉式(使用时创建)。
public class Singleton {private volatile static Singleton instance;private Singleton() {}public static Singleton getInstance() {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}return instance;}}桥接模式(Bridge):
将抽象和实现分离,使他们独立变化。即实现系统可能有多个分类,每个分类都有可能变化,就把每个变化分离出来,减少他们之间的藕合。
命令模式(Command):
将一个请求(command)封装成一个对象,从而可以让你用不同的请求对客户(receiver)进行参数化,对请求进行记录或日志,支持撤销操作(invoker)。
invoker通知command执行请求,command执行receiver的具体要求。
public class Mp3Player {public void playMusic() {System.out.println("Music is playing.");}public void stopMusic() {System.out.println("Music is stopped.");}}public interface Command {public void execute();public void undo();}public class PlayMusicCommand implements Command {private Mp3Player player;public PlayMusicCommand(Mp3Player p) {this.player = p;}public void execute() {this.player.playMusic();}public void undo() {this.player.stopMusic();}}// 停止音乐命令public class StopMusicCommand implements Command {private Mp3Player player;public StopMusicCommand(Mp3Player p) {this.player = p;}public void execute() {this.player.stopMusic();}public void undo() {this.player.playMusic();}}public class NoCommand implements Command {public void execute() {};public void undo() {};}public class remoteControl{private Command[] cm;private Command preCM;public remoteControl(){ cm = new Command[3]; for(int i =0;i< 3;i++){ cm[i] = new NoCommand(); }}public void setCommand(int index, Command c) {cm[index] = c;}public void doCommond(int index){cm[index].execute();preCM = cm[index];}public void cancleCommond(int index){preCM.undo();}}享元模式(Flyeight):
它用来解决大量相同对象被多次实例化,从而导致内存被大量占用的情况。享元模式中关键要理解“内蕴状态”(Internal State)和“外蕴状态”(External State)这两个概念。
内蕴状态:存储在享元对象内部,不随着环境改变,要以被诸多对象共享。
外蕴状态:一般由客户端指定,并传入享元对象内部,它随着环境进行变化。
抽象享元(Flyweight):为具体享元规定出需要实现的公共接口。
具体享元(ConcreteFlyweight):实现抽象享元角色所规定的接口。如果有“内蕴状态”的话,将“内蕴状态”声明为成员变量,从而使享元对象拥用固定的“内蕴状态”。
享元工厂(FlyweightFactory):负责创建和管理享元角色,保证享元对象可以被共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有符合要求的享元对象。如果已经有了,享元工厂就应当提供这个现有享元对象;如果系统中没有适当的享元对象,享元工厂角色就应当创建一个合适的享元对象。
客户端(Client):维护一个对所有享元对象的引用。提供与管理享元对象的“外蕴状态”。
解释器模式(Interpreter):
它建立一个解释器,对于特定的计算机程序设计语言,用来解释预先定义的文法。
访问者模式(Visitor):
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
1.Visitor 抽象访问者角色,为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具休访问者的具休元素角色,这样访问者就可以通过该元素角色的特定接口直接访问它。
2.ConcreteVisitor.具体访问者角色,实现Visitor声明的接口。
3.Element 定义一个接受访问操作(accept()),它以一个访问者(Visitor)作为参数。
4.ConcreteElement 具体元素,实现了抽象元素(Element)所定义的接受操作接口。
5.ObjectStructure 结构对象角色,这是使用访问者模式必备的角色。它具备以下特性:能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。