设计模式定义
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。由GOF在二十年前提出来的。
目的:为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
面向对象设计的六大基本原则(高内聚、低耦合)
面向对象设计的目标
1、可扩展性 容易添加新的功能
2、灵活性 容易添加新的功能代码修改平稳地发生(修改一处地方带来的影响尽量少)
3、可插入性 容易将一个类抽出去,同时将另一个有同样接口的类加入进来
4、可复用性强。
高内聚、低耦合
耦合性:也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息
内聚性:又称块内联系。指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。若一个模块内各元素(语名之间、程序段之间)联系的越紧密,则它的内聚性就越高。
高内聚是指一个软件模块是由相关性很强的代码组成,只负责一项任务,不可分割。
对于低耦合,一个完整的系统,模块与模块之间,尽可能的使其独立存在。也就是说,让每个模块,尽可能的独立完成某个特定的子功能。模块与模块之间的接口,尽量的少而简单。如果某两个模块间的关系比较复杂的话,最好首先考虑进一步的模块划分。这样有利于修改和组合。
六大基本原则
单一职责原则 SOP:一个类只负责一个功能领域中的相应职责。
开放封闭原则 OCP:对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
接口隔离原则 ISP:使用多个专一功能的接口比使用一个的总接口要好。
里氏替换原则 LSP:子类型必须能够替换它们的基类型。一个软件实体如果使用的是一个基类,那么当把这个基类替换成继承该基类的子类,程序的行为不会发生任何变化。软件实体察觉不出基类对象和子类对象的区别。
依赖倒置原则 DIP:要依赖于抽象,不要依赖于具体。客户端依赖于抽象耦合。
迪米特法则 LOD:对象与对象之间应该使用尽可能少的方法来关联,避免千丝万缕的关系。
单例设计模式
- 提出者是:GOF(gang of four)
应用场景
保证一个类在系统中只存在一个实例。如:客户端商城等项目中(涉及注册登录)的用户类,Windows的任务管理器,工厂模式中的工厂等等。
优点
由于单例模式只生成一个实例,减少了系统弄性能开销,当一个对象的产生需要较多的资源时,可通过在应用启动时直接产生单例对象,然后永久驻留内存的方式来解决。
常见的物种单例模式实现方式
- 饿汉式(线程安全,调用效率高(因为不用加锁),但是不能延时加载(需要的时候你再去创建对象))
/**
* 饿汉式
* 缺点:不能延时加载
*/
public class SingletonDemo1 {
//1.私有化构造
private SingletonDemo1(){
}
//2.生成一个实例对象,类加载的时候生成
private static SingletonDemo1 instance = new SingletonDemo1();
//3.向外提供一个公有、静态的方法提供该单例对象
public static SingletonDemo1 getInstance(){
return instance;
}
}
2. 懒汉式(资源利用效率高,实现了懒加载,但是并发调用效率低,由于每次都要加锁所以浪费系统资源)
/**
* 懒汉式
* 优点:延迟加载
* 缺点:加锁,调用效率低
*/
public class SingletonDemo2 {
//1.私有化构造
private SingletonDemo2(){
}
//2.声明一个私有的,静态的成员变量
private static SingletonDemo2 instance ;
//3.向外提供一个公有、静态的方法提供该单例对象
public static synchronized SingletonDemo2 getInstance(){
if (instance == null) {
instance = new SingletonDemo2();
}
return instance;
}
}
3. 双重检测锁(由于编译器优化原因,和JVM底层模型问题,偶尔会出问题,不建议使用)
/**
* 双重检测锁机制
*/
public class SingletonDemo3 {
//1.私有化构造
private SingletonDemo3(){
}
//2.声明一个私有的,静态的成员变量
private static SingletonDemo3 instance ;
//3.向外提供一个公有、静态的方法提供该单例对象
public static synchronized SingletonDemo3 getInstance(){
if (instance == null) {
//instance为空时加锁
synchronized (SingletonDemo3.class) {
if (instance == null) {
instance = new SingletonDemo3();
}
}
}
return instance;
}
}
- 静态内部类
- 外部类没有static,所以静态内部类不会在外部类加载的时候初始化,所以就实现了懒加载。
- 线程安全,因为实例对象是在静态内部类加载的时候创建,所以天然是单例的。
/**
* 静态内部类
* 1.延时加载
* 2.线程安全
* 外部类加载时内部类不会加载
*/
public class SingletonDemo4 {
//1.私有化构造
private SingletonDemo4(){
}
//2.声明一个静态内部类
private static class SingletonDemo4Instance{
//在静态内部类里面声明一个公有的、静态的成员变量,并赋值为外部类的单例对象
public static SingletonDemo4 instance = new SingletonDemo4();
}
//3.向外提供一个公有、静态的方法提供该单例对象
public static synchronized SingletonDemo4 getInstance(){
//内部类加载
return SingletonDemo4Instance.instance;
}
}
5. 枚举实现单例(线程安全,天然就是单例的,能避免反射和反序列化带来的问题,但是不能懒加载)。
/**
* 枚举
* 防止反射破坏单例,防止反序列化破坏单例
*/
public enum SingletonDemo5 {
INSTANCE;
}
**单例中的问题**
//反射
//第一步获取字节码文件
Class<SingleTon01> claz = SingleTon01.class;
//claz获得无参构造器
Constructor<SingleTon01> constructor = claz.getDeclaredConstructor(null);
constructor.setAccessible(true);
SingleTon01 instance2 = constructor.newInstance();
反射和反序列化会导致单例失效。
/**
* 在单例中如何防止反射和反序列化
*/
public class SingletonDemo6 implements Serializable{
/**
* 序列号
*/
private static final long serialVersionUID = -3652977293498762554L;
//1.私有化构造
private SingletonDemo6(){
if (instance != null) {
//已经生成对象,不能再调用该方法
throw new RuntimeException();
}
}
//2.声明一个私有的,静态的成员变量
private static SingletonDemo6 instance = new SingletonDemo6() ;
//3.向外提供一个公有、静态的方法提供该单例对象
public static synchronized SingletonDemo6 getInstance(){
return instance;
}
/**
* 反序列化通过该方法来获取反序列化后的对象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return instance;
}
}
## 简单工厂模式 又称为静态工厂模式##
**应用场景**
用来生产同一结构中的任意产品。
**缺点**
不符合“开放封闭原则”,要新创建产品的话就要去修改工厂类。
/**
* 动物工厂
*/
public class AnimalFactory {
public static Animal createAnimal(String animal){
if ("dog".equals(animal)) {
return new Dog();
} else if ("cat".equals(animal)) {
return new Cat();
}else {
return null;
}
}
}
## 工厂方法模式 ##
**应用场景**
用来生产同一等级结构中的固定产品。(支持增加任意产品)
**缺点**
虽然符合“开放封闭原则”,但是会增加很多个类。
/**
* 工厂基类
*/
public abstract class BaseFactory {
/**
* 生产动物
* @return
*/
public abstract Animal createAnimal();
}
/**
* 猫工厂
*/
public class CatFactory extends BaseFactory{
/**
* 生产猫
* @return
*/
public Animal createAnimal(){
return new Cat();
}
}
/**
* 狗工厂
*/
public class DogFactory extends BaseFactory{
/**
* 生产狗
* @return
*/
public Animal createAnimal(){
return new Dog();
}
}
## 抽象工厂模式 ##
**抽象工厂模式**
用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过你改过抽象工厂模式产生需要的对象是一种非常好的解决方式。
例子:高端汽车工厂创建高端发动机、高端座椅、高端轮胎,低端汽车工厂创建低端的。
/**
* 发动机
*/
public abstract class Engine {
public abstract void start();
}
/**
* 高端发动机
*/
class HighEngine extends Engine{
@Override
public void start() {
System.out.println("高端发动机提速特别快!");
}
}
/**
* 低端发动机
*/
class LowEngine extends Engine{
@Override
public void start() {
System.out.println("低端发动机启动非常慢!");
}
}
/**
* 座椅
*/
public abstract class Seat {
public abstract void Seat();
}
/**
* 高级座椅
*/
class HighSeat extends Seat{
@Override
public void Seat() {
System.out.println("真皮座椅!");
}
}
/**
* 低级座椅
*/
class LowSeat extends Seat{
@Override
public void Seat() {
System.out.println("仿皮座椅!");
}
}
/**
* 轮胎
*/
public abstract class Tyre {
public abstract void run();
}
/**
* 高级轮胎
*/
class HighTyre extends Tyre{
@Override
public void run() {
System.out.println("磨损很小!");
}
}
/**
* 低级轮胎
*/
class LowTyre extends Tyre{
@Override
public void run() {
System.out.println("磨损很大!");
}
}
/**
* 工厂基类
*/
public abstract class BaseFactory {
/**
* 生产发动机
* @return
*/
public abstract Engine createEngine();
/**
* 生产轮胎
* @return
*/
public abstract Tyre createTyre();
/**
* 生产座椅
* @return
*/
public abstract Seat createSeat();
}
/**
* 低端工厂
*/
public class LowFactory extends BaseFactory {
@Override
public Engine createEngine() {
return new LowEngine();
}
@Override
public Tyre createTyre() {
return new LowTyre();
}
@Override
public Seat createSeat() {
return new LowSeat();
}
}
/**
* 高端工厂
*/
public class HighFactory extends BaseFactory {
@Override
public Engine createEngine() {
return new HighEngine();
}
@Override
public Tyre createTyre() {
return new HighTyre();
}
@Override
public Seat createSeat() {
return new HighSeat();
}
}
## 建造者模式 ##
**场景**
创建一个对象时需要构建很多个小部分,然后按照一定的步骤装配起来。在使用的时候常常配合工厂模式来使用。实现了构建和装配的解耦。
* StringBuilder的append方法。
* DomBuilder。
组成部分
* CadillacCar:tyre,engine,seat
* CarBuilder:buildTyre,buildEngine,buildSeat构建者
* Director:directCar装配者,里面要传入builder对象
客户端只需要找装配者要产品,装配者找构建者要元件去装配
/**
*Cadillac汽车
*/
public class CadillacCar extends Car {
private Engine engine;
private Seat seat;
private Tyre tyre;
@Override
public void run() {
engine.start();
tyre.run();
seat.Seat();
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
public Seat getSeat() {
return seat;
}
public void setSeat(Seat seat) {
this.seat = seat;
}
public Tyre getTyre() {
return tyre;
}
public void setTyre(Tyre tyre) {
this.tyre = tyre;
}
}
/**
* 构建者,构建元件
*/
public class CadillacBuilder implements IBuilder {
@Override
public Engine buildEngine() {
//如果配合抽象工厂使用,效果是不是更佳?
return new HighEngine();
}
@Override
public Tyre buildTyre() {
return new HighTyre();
}
@Override
public Seat buildSeat() {
return new HighSeat();
}
}
/**
* 装配者,组装构建者构建的元件
*/
public class CadillacDerictor implements IDerictor {
@Override
public Car derictCar(IBuilder builder) {
CadillacCar car = new CadillacCar();
Engine engine = builder.buildEngine();
Tyre tyre = builder.buildTyre();
Seat seat = builder.buildSeat();
car.setEngine(engine);
car.setTyre(tyre);
car.setSeat(new LowSeat());
return car;
}
}
## 适配器模式 ##
**生活中的场景**
![](http://i.imgur.com/NbjEWkB.jpg)
**定义**
将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能在一起工作的那些类能够一起工作。
**模式中的角色**
* Client :客户,相当于我们的笔记本电脑。(只认USB接口)(接手代码之后,新写的功能类)
* 目标结构(Target):客户所期待的接口。目标接口可以是具体的或者抽象的类,也可以是接口。相当于USB接口
* 需要适配的类(Adaptee):可以理解成PS2接口。(相当于,以前的程序员遗留下来的类)
* 适配器(Adapter):通过包装一个需要适配的对象,把原有的接口转换成目标接口。
**客户Client想直接使用Adaptee,但是使用不了,那么我们就定义一个适配器Adapter,客户只需要跟Adapter打交道就行**
**类适配器**
Adapter 继承Adaptee、实现Target接口
**对象适配器**
使用组合的方式,实现Target接口,将Adaptee对象通过构造函数传入Adapter类中。
**接口适配器**
**工作中应用场景**
* 经常用来做旧系统改造和升级
* 学习中见过的场景InputStreamReader(InputStream)
/**
* 需要被适配的对象
*/
public class Adaptee {
public void handleRequest(){
System.out.println("原来的老代码");
}
}
/**
* 新增加的功能类
*/
public class Client {
public void test(Target target){
target.request();
}
}
/**
* 客户所期待的接口
*/
public interface Target {
void request();
}
/**
* 类适配器
*/
public class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
this.handleRequest();
}
}
/**
* 对象适配器
*/
public class ObjectAdapter implements Target{
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.handleRequest();
}
}
## 观察者模式 ##
**实际生活中的一些场景**
* 广播机制。
* 订阅邮件。
* 消息推送
**模式中的角色**
* 目标对象,Subject,被观察的对象,当它的状态变化时,它需要及时通知一系列的对象。
* Observer,观察者。
**通知观察者的方式**
* 推,每次都会通知以广播方式发给所有观察者,所有观察者只能被动接受。
* 拉,观察者只要知道有情况变化即可。至于什么时候获取内容,要不要获取内容,都可以由观察者自己决定。
**自定义观察者模式**
* Subject中有addObserver(Oberver o)和removeObserver(Observer o)方法添加或移除观察者,有notifyAllObservers()方法来通知所有观察者对象发生改变了。
* Observer,里面有updata方法,用于接收到改变通知后作出相应的更新。
/**
*观察者的接口
*/
public interface IObserver {
/**
* 接收到消息之后的反应
* @param object
*/
void updata(Object object);
}
/**
*被观察者的接口
*/
public interface ISubject {
/**
* 添加观察者
* @param observer
*/
void addObserver(IObserver observer);
/**
* 移除观察者
* @param observer
*/
void removeObserver(IObserver observer);
/**
* 通知所有观察者
*/
void notifyAllObservers();
}
/**
* 学生实现观察者
*/
public class Student implements IObserver{
@Override
public void updata(Object object) {
}
}
class ZhangSan implements IObserver{
@Override
public void updata(Object object) {
System.out.println("张三收到!" + object);
}
}
class Lisi implements IObserver{
@Override
public void updata(Object object) {
System.out.println("李四收到!" + object);
}
}
class WangWu implements IObserver{
@Override
public void updata(Object object) {
System.out.println("王五收到!" + object);
}
}
class ZhaoLiu implements IObserver{
@Override
public void updata(Object object) {
System.out.println("赵六收到!" + object);
}
}
class Lvdan implements IObserver{
@Override
public void updata(Object object) {
System.out.println("驴蛋收到!" + object);
}
}
/**
* 教师实现被观察者
*/
public class Teacher implements ISubject {
List<IObserver> observers = new ArrayList<>();
@Override
public void addObserver(IObserver observer) {
observers.add(observer);
}
@Override
public void removeObserver(IObserver observer) {
observers.remove(observer);
}
@Override
public void notifyAllObservers() {
for (int i = 0; i < observers.size(); i++) {
IObserver observer = observers.get(i);
observer.updata("老师这里有好资源!");
}
}
}
public static void main(String[] args) {
ZhangSan zhangSan = new ZhangSan();
Lisi lisi = new Lisi();
WangWu wangWu = new WangWu();
ZhaoLiu zhaoLiu = new ZhaoLiu();
Teacher teacher = new Teacher();
teacher.addObserver(zhangSan);
teacher.addObserver(lisi);
teacher.addObserver(wangWu);
teacher.removeObserver(wangWu);
teacher.addObserver(zhaoLiu);
//我这里有新资源了
teacher.notifyAllObservers();
}
**Java中内置的观察者**
* Observable 是一个类,目标对象/被观察者继承它 当数据发生改变时,调用setChanged()表示目标状态发生改变,调用notifyObservers(Object o)来通知所有的观察者
* Observer 是一个接口,观察者实现它,能接收到目标改变的值或对象
/**
* 雇主继承被观察者
*/
public class Employer extends Observable {
/**
* 数据更新
*/
public void update(Object object){
setChanged();
notifyObservers(object);
}
}
/**
* 雇员实现观察者
*/
public class Employee implements Observer {
/**
* 接收更新数据
*/
@Override
public void update(Observable o, Object arg) {
System.out.println("收到,"+arg);
}
}
@Test
public void test(){
Employee employee = new Employee();
Employer employer = new Employer();
employer.addObserver(employee);
employer.update("加班!");
}
## 代理模式 ##
**Proxy**
***核心作用***:
* 通过代理可以控制对对象的访问,以周杰伦为例:合作商找周杰伦演出包含流程:面谈、起草合同、收预付款、订机票、唱歌、收尾款。可以找一个经纪人(代理)来处理与核心业务无关的事情、周杰伦只负责唱歌即可。而且一个经纪人可以代理很多明星。
* 微商,代理一款产品,实际发货的是——大老板,发朋友圈、和人聊天、拉下线、确定购买意向、收款、求好评等等。
* 代理可以详细控制访问某个对象的方法,在调用该方法钱做前置处理,调用这个方法后做后置处理。
***核心角色***:
* 抽象角色:定义代理角色和真实角色的公共对外方法,代理角色与真是角色都得去实现抽象角色。
* 真实角色:实现抽象角色,定义真实角所要实现的业务逻辑,供代理角色调用。
* 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。(将统一的流程控制代码放到代理类中处理)
***应用场景***
* 安全代理:屏蔽客户对真实角色的直接访问
* 远程代理:通过代理类处理远程方法的调用。
* 延迟加载: 先加载轻量级的代理对象,真正需要再加载真实对象。(如大图片问题)。
***分类***
* 静态代理(静态定义代理类)
* 动态代理(动态生成代理类)
* JDK中自带的动态代理
***静态代理案例***
* MaskFactory接口:包含发货方法
* MaskFactory类:真实角色,真正负责发货。
* ProxyMaskFactory:代理类,里面传入真实对象实现发货。
***缺点***
* 1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
* 2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。 相较静态代理的优点:抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样我们可以更加灵活和统一的处理众多的方法。
/**
* 公司
* 抽象角色,里面定义的是代理角色与真实角色的共同方法
*/
public interface Company {
/**
* 商演活动
*/
public abstract void performance();
}
/**
* 明星
*/
public class Star implements Company{
@Override
public void performance() {
System.out.println("在深圳表演");
}
}
/**
* 经纪人
*/
public class Agent implements Company {
private Company company;
public Agent(Company company){
this.company = company;
}
@Override
public void performance() {
System.out.println("买机票");
//调用明星的表演方法
company.performance();
System.out.println("收尾款");
}
}
***动态代理***
* 动态代理里面抽象角色只能是接口
* java.lang.reflect.Proxy
* 作用:动态生成代理类和对象,Proxy.newProxyInstance
* java.lang.reflect.InvocationHandler(处理器接口)
* 可以通过invoke方法实现对真实角色的访问。method.invoke
* 每次通过Proxy生成代理类对象时都要指定对应的处理器对象。
/**
* 公司
* 抽象角色,里面定义的是代理角色与真实角色的共同方法
*/
public interface Company {
/**
* 商演活动
*/
void performance();
/**
* 与粉丝互动
*/
void interaction();
}
/**
* 明星
*/
public class Star implements Company{
@Override
public void performance() {
System.out.println("在深圳表演");
}
@Override
public void interaction() {
System.out.println("与粉丝互动");
}
}
/**
* 票
*/
public interface Ticket {
/**
* 买票
*/
void buyTicket();
}
/**
* 机票
*/
public class AirTicket implements Ticket {
/**
* 买机票
*/
@Override
public void buyTicket() {
System.out.println("代理买机票");
}
}
/**
* 经纪人
*/
public class Agent implements InvocationHandler {
private Object obj;
/**
* 代理明星谈一场商演
* @param obj
* @return
*/
public Object deal(Object obj){
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("谈价格");
//调用明星的表演方法
method.invoke(obj, args);
System.out.println("收尾款");
return null;
}
}
@Test
public void test(){
Agent agent = new Agent();
Company company = (Company) agent.deal(new Star());
company.performance();
company.interaction();
//换活动,代理商演改代理买机票
// Ticket ticket = (Ticket) agent.deal(new AirTicket());
// ticket.buyTicket();
}
## 装饰者模式 ##
***职责***
* 动态的为一个对象增加新的功能。
* 装饰模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代理继承关系,更加灵活,同时避免类型体系的快速膨胀。
* 例子:各种各样的车(飞行、潜水、人工智能)
public String download(String urlStr){
StringBuffer sb = new StringBuffer();
String line = null;
BufferedReader buffer = null;
try {
url = new URL(urlStr);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
//装饰者模式
buffer = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
while ((line = buffer.readLine()) != null){
sb.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}
finally{
try {
buffer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
***实现细节(装饰者和被装饰者实现共同的父类,将被装饰者对象传入装饰者中)***
* Component:抽象构件角色
* 被装饰对象和装饰对象有相同的父类。这样,客户端对象就能够以与被装饰对象相同的方式与装饰对象交互。
* ConcreteComponent:具体构件角色(被装饰对象)
* Decorator:装饰角色
* 持有一个抽象构件的引用。装饰对象接收所有客户端的请求,并把这些请求转发给真实的对象(被装饰对象)。这样,就能在真实对象(被装饰对象)调用前后增加新的功能。
* ConcreteDecorator:具体装饰角色
* 负责给真实对象(被装饰对象)增加新的功能。
***常见的应用场景***
* IO流中的Reader r = new BufferedReader(new InputStream(new File("xxxx.txt")));
/**
*抽象构件角色
*/
public abstract class Vehicle {
public abstract void run();
}
/**
*装饰者,持有被装饰者的引用
*/
public abstract class SurperVehicle extends Vehicle {
public Vehicle vehicle;
public SurperVehicle(Vehicle vehicle) {
super();
this.vehicle = vehicle;
}
}
/**
*被装饰者
*/
public class Car extends Vehicle {
@Override
public void run() {
System.out.println("可以在陆地上跑!");
}
}
/**
* 自动驾驶汽车
*/
public class AutoCar extends SurperVehicle {
public AutoCar(Vehicle vehicle) {
super(vehicle);
}
public void autoRun(){
System.out.println("可以自动驾驶!");
}
@Override
public void run() {
autoRun();
vehicle.run();
}
}
## 策略模式 ##
**场景**某个市场人员接到单后的报价策略。报价策略很复杂,可以简单做如下分类:
* 普通客户小批量报价
* 普通客户大批量报价
* 老客户小批量报价
* 老客户大批量报价
具体采用哪个报价策略,这需要根据实际情况来确定,这时候我们就可以采用策略模式。
可以采用条件判断来实现策略,但是不符合“开放封闭原则”,而且随着逻辑越来越复杂,代码也越来越冗余。
**定义:**策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某个问题,同时可以方便的更换算法或者增加新的算法。并且由客户端决定调用哪个算法。
**组成部分:**
* Manager:里面包含算法实例对象和具体的实现方法,负责和具体的策略类打交道,客户端直接与Manager类打交道即可。
* Strategy:算法接口
* 具体的算法类。
/**
*策略接口
*/
public interface IStrategy {
/**
* 展示价格
* @param price
* @return
*/
double showPrice(double price);
}
public class NewBigStrategy implements IStrategy {
@Override
public double showPrice(double price) {
return price*0.90;
}
}
public class NewLittleStrategy implements IStrategy {
@Override
public double showPrice(double price) {
return price*0.98;
}
}
public class OldBigStrategy implements IStrategy {
@Override
public double showPrice(double price) {
return price*0.8;
}
}
public class OldLittleStrategy implements IStrategy {
@Override
public double showPrice(double price) {
return price*0.88;
}
}
/**
*策略管理类,客户端只要跟这个类打交道就ok。
*/
public class StrategyManager {
public double showPrice(IStrategy strategy,double price){
return strategy.showPrice(price);
}
}
public static void main(String[] args) {
StrategyManager strategyManager = new StrategyManager();
double price = strategyManager.showPrice(new OldLittleStrategy(), 100);
System.out.println(price);
}
“`
前端控制器模式
前端控制器模式:是用来提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理,该处理程序可以做认证/授权/记录日志,或者跟踪请求,然后把请求传给然后把请求传给相应的处理程序。
案例:struts2的前端控制器StrutsPrepareAndExecuteFilter
责任链模式
责任链模式:为请求创建了一个接收者对象的链,这种模式给予请求的类型,对请求的发送者和接收者进行解耦,这种类型的设计模式属于行为型模式.