策略者模式
使用背景:
当写好代码打包发布给别人使用时,别人如果需要对代码进行扩展,传统类封装的方式就显得十分不方便。
这时策略者模式就闪亮登场了,因为策略者模式遵循开闭原则:对修改关闭,对扩展开放。
下面是一个计算器使用策略者模式实现的例子
public class Strategy {
/**
* 操作接口
*/
interface Operation{
public int doOperation(int n,int m);
}
/**
* 定义实现具体操作
*/
class OperationAdd implements Operation{
@Override
public int doOperation(int n, int m) {
return n + m;
}
}
/**
* 定义实现具体操作
*/
class OperationSub implements Operation{
@Override
public int doOperation(int n, int m) {
return n - m;
}
}
/**
* 计算器类
*/
class Calculator{
private Operation operation;
public void setOperation(Operation operation) {
this.operation = operation;
}
public int doOperation(int n,int m){
return operation.doOperation(n,m);
}
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
Strategy demo = new Strategy();
Calculator calculator = demo.new Calculator();
calculator.setOperation(demo.new OperationAdd());
System.out.println(calculator.doOperation(1, 2));
}
}
优点:
遵循了开闭原则,扩展性良好。
缺点:
随着你的策略增加,你的类也会越来越多。所有的策略类都要暴露出去,所以如果你在实际开发中使用了策略模式,一定要记得写好文档让你的伙伴们知道已有哪些策略。
装饰者模式
使用背景:当我们需要在原生类上扩展新的功能时,传统修改原生类的方式会带来很大的不便。
这时就应该使用装饰者模式对原生类进行动态的扩展。
下面就是一个装饰者模式的简单应用
public class Decorator {
/**
* 被装饰对象
*/
interface Person{
int doOperation();
void show();
}
/**
* 装饰器的超类
*/
abstract class DecoratorPerson implements Person{
protected Person person;
public DecoratorPerson(Person person) {
this.person = person;
}
}
/**
* 未被装饰前对象
*/
class NoDecoratorPerson implements Person{
@Override
public int doOperation() {
return 0;
}
@Override
public void show() {
System.out.println("未被装饰:"+this.doOperation());
}
}
/**
* A装饰后
*/
class DecoratorPersonByA extends DecoratorPerson{
public DecoratorPersonByA(Person person) {
super(person);
}
@Override
public int doOperation() {
return person.doOperation() + 10;
}
@Override
public void show() {
person.show();
System.out.println("A装饰后:"+this.doOperation());
}
}
/**
* B装饰后
*/
class DecoratorPersonByB extends DecoratorPerson{
public DecoratorPersonByB(Person person) {
super(person);
}
@Override
public int doOperation() {
return person.doOperation() + 20;
}
@Override
public void show() {
person.show();
System.out.println("B装饰后:"+this.doOperation());
}
}
public static void main(String[] args) {
Decorator demo = new Decorator();
Person a = demo.new NoDecoratorPerson();
a = demo.new DecoratorPersonByA(a);
a = demo.new DecoratorPersonByB(a);
a.show();
System.out.println("最终:"+a.doOperation());
}
}
通过使用装饰器接口,需要对原生类进行扩展时,便可以通过实现类装饰便可以完成对原生类的动态扩展,遵循了开闭原则。
Java 中的 IO 流便是使用了这种装饰器模式:
可以发现InputStream其实就是被装饰对象的超类,StringBufferInputStream等就是被装饰的对象,
FilterInputStream就是装饰器的父类,其他则是具体的装饰器。
观察者模式
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通 知并自动更新。
例子
/**
* 观察者模式
*/
public class Observer {
/**
* 观察者
*/
abstract class Customer {
abstract void update();
}
/**
* 观察者A
*/
class CustomerA extends Customer{
@Override
void update() {
System.out.println("A收到了更新消息!!!");
}
}
/**
* 观察者B
*/
class CustomerB extends Customer{
@Override
void update() {
System.out.println("B收到了更新消息!!!");
}
}
/**
* 基础接口
*/
interface ISubject{
void registerObserver(Customer customer);
void removeObserver(Customer customer);
void doUpdate();
}
/**
* 被观察者
*/
class BeObserved implements ISubject{
List<Customer> customers = new ArrayList<>();
//添加观察者
@Override
public void registerObserver(Customer customer) {
this.customers.add(customer);
}
@Override
public void removeObserver(Customer customer) {
this.customers.remove(customer);
}
//更新消息
@Override
public void doUpdate(){
for (Customer customer : customers) {
customer.update();
}
}
}
public static void main(String[] args) {
Observer demo = new Observer();
Customer a = demo.new CustomerA();
Customer b = demo.new CustomerB();
BeObserved beObserved = demo.new BeObserved();
beObserved.registerObserver(a);
beObserved.registerObserver(b);
beObserved.doUpdate();
}
}
java原生提供了Observe和Observable两个接口用于实现观察者模式
/**
* jdk原生的观察者模式
*/
public class ObserverByJdk {
class CustomerA implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("A收到了更新!!!");
}
}
class CustomerB implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("B收到了更新!!!");
}
}
class BeObserved extends Observable{
public void doUpdate() {
this.setChanged();
this.notifyObservers();
}
}
public static void main(String[] args) {
ObserverByJdk demo = new ObserverByJdk();
Observer a = demo.new CustomerA();
Observer b = demo.new CustomerB();
Observable observed = demo.new BeObserved();
observed.addObserver(b);
observed.addObserver(a);
((BeObserved) observed).doUpdate();
}
}
优点:
观察者和被观察之间抽象耦合,自有一套触发机制,被观察者无需知道通知对象是谁,只要是符合观察者接口的就可以。
缺点:
观察者只知道被观察发生变化,而无法知道是如何发生变化的,比如是修改了 name 字段还是其他,观察者都不知道。如果有很多个观察者,一个个通知比较耗时。