7.策略模式
策略模式是指一个用户具有某个行为,但在不同的环境下,该行为有不同的实现算法。
本质:分离算法,选择实现
角色:抽象策略角色:策略类,通常由一个接口或抽象类实现。
具体策略角色:包装了相关算法和行为。
环境角色:持有策略类的一个引用,最终给客户端进行调用。
以crm客户关系管理为例:购买一款产品可以分为:新用户大量购买、新用户少量购买价、老用户大量购买、老用户少量购买。采用策略模式实现方式如下:
/** * 策略类 * @author Administrator * */ public interface Strategy { public double getPrice(Double price); } /** * 新客户少量购买 * @author Administrator * */ public class NewCustomerFewStrategy implements Strategy{ @Override public double getPrice(Double price) { // TODO Auto-generated method stub System.out.println("新客户"); return price; } } public class NewCustomerManyStrategy implements Strategy{ @Override public double getPrice(Double price) { // TODO Auto-generated method stub System.out.println("新客户大量"); return price *0.6; } } public class OldCustomerFewStrategy implements Strategy{ @Override public double getPrice(Double price) { // TODO Auto-generated method stub System.out.println("老客户少量"); return price * 0.8; } } public class OldCustomerManyStrategy implements Strategy{ @Override public double getPrice(Double price) { // TODO Auto-generated method stub System.out.println("老客户大量"); return price*0.6; } } /** * 环境角色 * @author Administrator * */ public class Context { private Strategy strategy; public Context(Strategy strategy) { super(); this.strategy = strategy; } public double getPrice(double price){ return this.strategy.getPrice(price); } } /** * 测试 * @author Administrator * */ public class TestStrategy { public static void main(String[] args) { Context context = new Context(new OldCustomerManyStrategy()); double price = context.getPrice(999); System.out.println(price); } }
运行结果:
老客户大量
599.4
8.适配器模式
适配器就是一种适配中间件,它存在于不匹配的两者之间,用于连接二者,将不匹配变为匹配。它分为:类适配器、对象适配器以及接口适配器
学习中遇到:InputstreamReader(InputStream)、OutputStreamReader(OutputStream)
应用场景:系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码,创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,
包括一些可能在将来引进的类一起工作
public interface Target { public void fun(); } /** * 适配器 * @author Administrator * */ public class Adapter implements Target{ private Adaptee adaptee; @Override public void fun() { // TODO Auto-generated method stub adaptee.fun(); } public Adapter(Adaptee adaptee) { super(); this.adaptee = adaptee; } } /** * 被适配对象 * @author Administrator * */ public class Adaptee { public void fun(){ System.out.println("适配器模式"); } }
/** * 客户端 * @author Administrator * */ public class Client { public void fun(Target target){ target.fun(); } public static void main(String[] args) { Client client = new Client(); Adaptee adaptee = new Adaptee(); Target target = new Adapter(adaptee); client.fun(target); } }
运行结果:适配器模式
优点:
1:将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无需修改原有结构。
2:增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一适配者类可以在多个不同的系统中复用。
3:灵活性和扩展性都非常好,通过使用配置文件,可以很方便的更换适配器,也可以在不修改原有代码的基础上 增加新的适配器,完全复合开闭原则。
缺点:
1:一次最多只能适配一个适配者类,不能同时适配多个适配者。
2:适配者类不能为最终类,在C#中不能为sealed类
3:目标抽象类只能为接口,不能为类,其使用有一定的局限性。
9.代理模式
定义:代理模式给某一个对象创建一个代理对象,并将该对象的引用给代理对象,让代理对象实现对该对象控制。类似于中介。
类图如下:
代理模式作用:
- 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
1.静态代理
/** 接口 **/ public interface Star { public void confer(); public void signconnect(); public void bookTicket(); public void sing(); public void collectMoney(); } /** * 委托类 * @author Administrator * */ public class StarReal implements Star{ @Override public void confer() { // TODO Auto-generated method stub } @Override public void signconnect() { // TODO Auto-generated method stub } @Override public void bookTicket() { // TODO Auto-generated method stub } @Override public void sing() { // TODO Auto-generated method stub System.out.println("歌手唱歌"); } @Override public void collectMoney() { // TODO Auto-generated method stub } } /** * 代理角色 * @author Administrator * */ public class ProxyReal implements Star{ private Star star; @Override public void confer() { // TODO Auto-generated method stub System.out.println("面谈"); } public ProxyReal(Star star) { super(); this.star = star; } @Override public void signconnect() { // TODO Auto-generated method stub System.out.println("与粉丝联系"); } @Override public void bookTicket() { // TODO Auto-generated method stub } @Override public void sing() { // TODO Auto-generated method stub //请歌手唱歌 代理 System.out.println("请歌手唱歌"); star.sing(); } @Override public void collectMoney() { // TODO Auto-generated method stub } } /** * 客户端 * @author Administrator * */ public class Client { public static void main(String[] args) { Star star = new StarReal(); ProxyReal proxyReal = new ProxyReal(star); proxyReal.sing(); } } 运行结果: 请歌手唱歌 歌手唱歌
静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
动态代理:
public interface Star { public void sing(); } //被代理对象 public class RealStar implements Star { @Override public void sing() { // TODO Auto-generated method stub System.out.println("周杰伦唱歌"); } } //代理类 public class StarHandler implements InvocationHandler{ private Star realStar; public StarHandler(Star realStar) { super(); this.realStar = realStar; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object object = null; System.out.println("联系粉丝、 买票"); method.invoke(realStar, args); System.out.println("收钱"); return object; } } //客户端 public class Client { public static void main(String[] args) { Star realStar = new RealStar(); StarHandler starHandler = new StarHandler(realStar); Star proxy= (Star)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, starHandler); proxy.sing(); } }
运行结果:
联系粉丝、 买票
周杰伦唱歌
收钱
很明显,适配器模式是因为新旧接口不一致导致出现了客户端无法得到满足的问题,但是,由于旧的接口是不能被完全重构掉的,因为我们还想使用实现了这个接口的一些服务。那么为了使用以前实现旧接口的服务,我们就应该把新的接口转换成旧接口;实现这个转换的类就是抽象意义的转换器。
相比于适配器的应用场景,代理就不一样了,虽然代理也同样是增加了一层,但是,代理提供的接口和原本的接口是一样的,代理模式的作用是不把实现直接暴露给client,而是通过代理这个层,代理能够做一些处理。
10.桥接模式
定义:桥接模式将抽象部分与它们的实现部分分离开来,使它们可以独立的变化。桥接模式将类与类的继承模式转换成类之间的关联关系,降低类之间的耦合关系,减少了类的数量。
public interface Color { public void bepaint(String shape); } class White implements Color{ @Override public void bepaint(String shape) { // TODO Auto-generated method stub System.out.println("白色的"+shape); } } class Black implements Color{ @Override public void bepaint(String shape) { // TODO Auto-generated method stub System.out.println("黑色的"+shape); } } public abstract class Shape { Color color; public void setColor(Color color) { this.color = color; } public abstract void draw(); } /** * 定义长方体 * @author Administrator * */ class Square extends Shape{ @Override public void draw() { // TODO Auto-generated method stub color.bepaint("长方形"); } } /** * 正方体 */ class Circle extends Shape{ @Override public void draw() { // TODO Auto-generated method stub color.bepaint("正方体"); } } public class Client { public static void main(String[] args) { Color white = new White(); Shape circle = new Circle(); circle.setColor(white); circle.draw(); } }
运行结果:
白色的正方体
11.组合模式
组合模式允许你将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象以及对象的组合。
组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。
- 组合部件(Component):它是一个抽象角色,为要组合的对象提供统一的接口。
- 叶子(Leaf):在组合中表示子节点对象,叶子节点不能有子节点。
- 合成部件(Composite):定义有枝节点的行为,用来存储部件,实现在Component接口中的有关操作,如增加(Add)和删除(Remove)。
import java.util.*; public class Client{ public static void main(String []args){ ImageFile f2= new ImageFile("nba.png"); Folder f1 = new Folder("Text File"); f1.add(f2); f1.killVirus(); } }
//抽象构建角色 interface AbstractFile { void killVirus(); }
//叶子节点构建角色 class ImageFile implements AbstractFile{ String name; public void killVirus(){ System.out.println("imageFile:"+name+" is killed"); } public ImageFile(String name){ this.name = name; } } class TextFile implements AbstractFile{ String name; public void killVirus(){ System.out.println("TextFile:"+name+" is killed"); } public TextFile(String name){ this.name = name; } }
//容器构建角色 class Folder implements AbstractFile{ private String name; private List<AbstractFile>list = new ArrayList<AbstractFile>(); public void killVirus(){ System.out.println("Floder "+name+" is killed"); for(AbstractFile file:list){ file.killVirus(); } } public void add(AbstractFile file){ list.add(file); } public Folder(String name){ this.name = name; } }
运行结果:
Floder Text File is killed
imageFile:nba.png is killed