我是靠谱客的博主 仁爱外套,这篇文章主要介绍设计模式8,外观模式、装饰者模式、适配器模式外观模式装饰者模式适配器模式,现在分享给大家,希望可以做个参考。

目录

外观模式

装饰者模式

适配器模式


外观模式

外观模式提供了一个统一的接口,用来访问子系统中的一群接口。

类型:结构型

使用场景:当子系统越来越复杂的时候,增加外观模式可以提供简单调用接口。构建多层系统结构的时候,利用外观对象作为每层的入口,简化层间调用。

优点:简化调用过程,无需深入了解子系统,防止带来风险。减少系统以来,松散耦合。更好的划分访问层次。符合迪米特法则。

缺点:增加、扩展子系统的行为容易引入风险。不符合开闭原则。

例子:

复制代码
1
2
3
4
5
6
7
8
9
10
11
public class Goods { private String name; public Goods(String name) { this.name = name; } public String getName() { return name; } }
复制代码
1
2
3
4
5
6
public class OrderService { public boolean isAvailable(Goods goods){ System.out.println("商品:" + goods.getName() + ",库存校验通过,下单成功"); return true; } }
复制代码
1
2
3
4
5
6
public class PaymentService { public boolean pay(Goods goods){ System.out.println("支付" + goods.getName() + "成功"); return true; } }
复制代码
1
2
3
4
5
6
7
public class ShippingService { public String shipGoods(Goods goods){ System.out.println(goods + "进入物流系统"); String orderNum = "101"; return orderNum; } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class StoreService { private OrderService orderService; private PaymentService paymentService; private ShippingService shippingService; public void setOrderService(OrderService orderService) { this.orderService = orderService; } public void setPaymentService(PaymentService paymentService) { this.paymentService = paymentService; } public void setShippingService(ShippingService shippingService) { this.shippingService = shippingService; } public void goodsSell(Goods goods){ if(orderService.isAvailable(goods)){ if(paymentService.pay(goods)){ String shippingNum = shippingService.shipGoods(goods); System.out.println("下单成功,订单号:" + shippingNum); } } } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
public class Test { public static void main(String[] args) { Goods goods = new Goods("衣服"); StoreService storeService = new StoreService(); storeService.setOrderService(new OrderService()); storeService.setPaymentService(new PaymentService()); storeService.setShippingService(new ShippingService()); storeService.goodsSell(goods); } }

看下类图

事实上这种方式并不符合外观模式,对于外观模式,应用层只需要和StoreService关联就好,不需要跟其他Service关联,而这里在应用层也创建了其他service,所以需要调整一下代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StoreService { private OrderService orderService = new OrderService(); private PaymentService paymentService = new PaymentService(); private ShippingService shippingService = new ShippingService(); public void goodsSell(Goods goods){ if(orderService.isAvailable(goods)){ if(paymentService.pay(goods)){ String shippingNum = shippingService.shipGoods(goods); System.out.println("下单成功,订单号:" + shippingNum); } } } }
复制代码
1
2
3
4
5
6
7
public class Test { public static void main(String[] args) { Goods goods = new Goods("衣服"); StoreService storeService = new StoreService(); storeService.goodsSell(goods); } }

再看类图

这样才符合外观模式。

用到设计模式的源码:

Configuration#newMetaObject主要看其被调用的方法,调用方法想要一个MetaObject,只需要调Configuration这个方法就好,而不需要直接和MetaObject有关系。


装饰者模式

在不改变原油对象的基础上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象功能)。

我们通常使用继承进行扩展,但如果扩展的功能种类繁多,那就会生成很多子类来增加系统的复杂性。并且使用继承扩展,必须可预见这些功能。

类型:结构型

使用场景:扩展一个类的功能或给一个类添加附加职责。动态给一个兑现更添加功能,这些功能可以再动态撤销。

优点:是继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能。通过使用不同的装饰类以及这些装饰类的排列组合,可以实现不同的效果。符合开闭原则。

缺点:会出现更多代码,更多的对象,增加系统复杂性。动态或多层装饰会更复杂。

例子:

复制代码
1
2
3
4
5
6
7
8
public class Cake { protected String getName(){ return "蛋糕"; } protected int price(){ return 10; } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
public class MangoCake extends Cake{ @Override public String getName() { return "芒果" + super.getName(); } @Override public int price() { return super.price() + 5; } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
public class MangoAppleCake extends MangoCake { @Override public String getName() { return "苹果" + super.getName(); } @Override public int price() { return super.price() + 6; } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
public class Test { public static void main(String[] args) { Cake cake = new Cake(); System.out.println(cake.getName() + ",价格:" + cake.price()); cake = new MangoCake(); System.out.println(cake.getName() + ",价格:" + cake.price()); cake = new MangoAppleCake(); System.out.println(cake.getName() + ",价格:" + cake.price()); } }

 这种写法对于扩展来说非常困难,蛋糕有各种各样的,如果我还想要别的种类,那还要加更多的类,更麻烦,于是用装饰者模式试试:

复制代码
1
2
3
4
public abstract class AbstractCake { protected abstract String getName(); protected abstract int price(); }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class AbstractDecorator extends AbstractCake { private AbstractCake aCake; public AbstractDecorator(AbstractCake aCake) { this.aCake = aCake; } @Override protected String getName() { return this.aCake.getName(); } @Override protected int price() { return this.aCake.price(); } }
复制代码
1
2
3
4
5
6
7
8
public class Cake extends AbstractCake { protected String getName(){ return "蛋糕"; } protected int price(){ return 10; } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Apple extends AbstractDecorator { public Apple(AbstractCake aCake) { super(aCake); } @Override protected String getName() { return "苹果" + super.getName(); } @Override protected int price() { return super.price() + 6; } }
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Mango extends AbstractDecorator{ public Mango(AbstractCake aCake) { super(aCake); } @Override public String getName() { return "芒果" + super.getName(); } @Override public int price() { return super.price() + 5; } }
复制代码
1
2
3
4
5
6
7
8
9
public class Test { public static void main(String[] args) { AbstractCake cake = new Cake(); cake = new Mango(cake); cake = new Mango(cake); cake = new Apple(cake); System.out.println(cake.getName() + ",价格:" + cake.price()); } }

再看下类图:

用这种方式,可以很自由的选择加什么东西,扩展起来也更方便。

 用到设计模式的源码:

BufferedReader继承Reader,并且用in来构建BufferedReader

ServletRequest

直接看类图:

mybatis中的Cache

 上面decorators中的类都是cache的装饰类,可以自己去看看。


适配器模式

将一个类的接口(被适配者)转换成客户期望的另一个接口(目标)。使原本不兼容的类可以一起工作。

类型:结构型

使用场景:已经存在的类的方法和需求不匹配时(方法和结果相同或相似)。不是软件设计阶段考虑的设计模式,而是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同的情况下的解决方案。

优点:能提高类的透明性和复用性,现有的类复用但不需要改变。目标类和适配器类解耦,提高程序的扩展性。符合开闭原则。

缺点:在编写过程中要全面考虑,可能会在增加系统的复杂性。增加系统代码的可读难度。

例子:

类适配器模式:通过集成获取被适配者的方法,并修改为自己的实现。

复制代码
1
2
3
4
5
public class Adaptee { public void adapteeRequest(){ System.out.println("被适配者的方法"); } }
复制代码
1
2
3
public interface Target { void request(); }
复制代码
1
2
3
4
5
6
public class ConcreteTarget implements Target { @Override public void request() { System.out.println("ConcreteTarget目标方法"); } }
复制代码
1
2
3
4
5
6
public class Adapter extends Adaptee implements Target { @Override public void request() { super.adapteeRequest(); } }
复制代码
1
2
3
4
5
6
7
8
9
10
public class Test { public static void main(String[] args) { Target target = new ConcreteTarget(); target.request(); Target adapterTarget = new Adapter(); adapterTarget.request(); } }

 类图:

目标方法通过Target的接口,Target通过Adapter移交给了被适配者(Adaptee)

对象适配器模式

一个场景:电源适配器,从220v交流电转换为手机可用的5v直流电

复制代码
1
2
3
4
5
6
7
public class AC220 { public int outputAC220V(){ int output = 220; System.out.println("输入交流电" + output + "V"); return output; } }
复制代码
1
2
3
public interface DC5 { int outputDC5V(); }
复制代码
1
2
3
4
5
6
7
8
9
10
11
public class PowerAdapter implements DC5 { private AC220 ac220 = new AC220(); @Override public int outputDC5V() { int adapterInput = ac220.outputAC220V(); int adapterOutput = adapterInput / 44; System.out.println("使用适配器,输入" + adapterInput + ",输出" + adapterOutput); return adapterOutput; } }
复制代码
1
2
3
4
5
6
public class Test { public static void main(String[] args) { DC5 dc5 = new PowerAdapter(); dc5.outputDC5V(); } }

类图:

 用到设计模式的源码:

例如XmlAdapter

xml读取的一个抽象类,用的时候继承这个类并实现相关接口

其实适配器模式在spring启动配置时经常用到,我们在之前springboot的源码分析中也可以见到大量的Adapter,DispatcherServlet#doDispatch中

因为会传入若干handler,那也有若干适配器与他匹配,适配器实现HandlerAdapter接口。

最后

以上就是仁爱外套最近收集整理的关于设计模式8,外观模式、装饰者模式、适配器模式外观模式装饰者模式适配器模式的全部内容,更多相关设计模式8内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(82)

评论列表共有 0 条评论

立即
投稿
返回
顶部