1.怎么掌握设计模式? 独孤5剑 先是锋利的剑 后面是无剑才是最强的
,GOF四人组写的<设计模式>书,包含了23种,实际可能还有其他,不要被束缚(只是覆盖了大部分).设计模式适合的人群:
1.不知道设计模式
2.有编程经验,但是写的好多代码有设计模式却不知道
3.学习过设计模式,发现有些模式好用
4.需要阅读别人的源码和框架,和设计模式
5.以前没有意识的使用设计模式,学习完恍然大悟
2.设计模式类型(4种类型,23种)
- 创建型模式(类的创建) 单例模式(怎么只创建1个类*) 抽象工厂模式 原型模式 建造者模式,工厂模式(*)
- 结构型模式(系统性问题,整个系统代码量达到大量的级别) 适配器模式,桥接模式,访问者模式 迭代器模式,观察者模式,中介者模式,忘备录模式
解释器模式(interpreter),策略模式,装饰模式(解决类多到爆炸*)- 行为型模式(方法的角度) 模板方法模式 职责链(责任链,方法的调用顺序)
3.单例模式(8种方法) 保证系统中 某个类只能存在一个对象实例,类只提供一个得到对象的方法(静态方法)
1.饿汉式singleton(立即创建对象) 优点:避免多线程同步问题(常用于单线程),写法简单 缺点: 不确定什么时候被其他类加载,造成不必要的内存浪费,不能lazy loading的效果
class Singleton{ //线程安全
//1.私有的构造器
private Singleton(){}
//2.类内部直接创建对象实例
private final static Singleton instance=new Singleton();
//3.暴露一个静态方法返回对象
public static Singleton getInstance(){
return instance;
}
}
2.饿汉式 (创建放在)静态代码块 优缺点和1一样
private final static Singleton instance;
static{
instance=new Singleton();
}
3.懒汉式1(线程不安全)(静态方法调用时才创建对象) 优点:可以起到懒加载效果 缺点: 多线程会出现线程同步问题 (if判断的时候其他线程也同时判断)开发时不要使用它
public static Singleton getInstance(){
if(instance == null){
instance=new Singleton();
}
return instance;
}
4.懒汉式2(线程安全) 方法上加synchronized 优点: 解决线程安全问题 缺点: 效率太低(new了实例后,后面得到实例都需要经过同步方法) 开发不推荐使用
public static synchronized Singleton getInstance(){
if(instance == null){
instance=new Singleton();
}
return instance;
}
5.这种懒汉式 不能解决线程安全问题 开发不能用
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){ //一个线程执行完,另外同一时间执行的一个线程也会等待执行里面的语句
instance=new Singleton();
}
}
return instance;
}
6.双重检查(使用volatile关键字和双重检查对象是否被创建) 推荐使用 优点: 解决效率(懒加载)和同步的问题
private final static volatile Singleton instance=new Singleton(); //可以要加volatile 不是因为线程同步的问题,而是指令重排导致instance被提前赋值的问题
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){ //为什么要多判断一次呢?,由于5他可能有线程同步问题
// 这里的instance已经写了volatile(可见性,不能保证原子性.防止指令重排序)但是不能保证线程同步
instance=new Singleton();
}
}
}
return instance;
}
- 静态内部类(有静态内部类变量new,返回对象是static静态内部类也是static) 优点保证了线程安全
1.加载外部类的时候不会加载内部类
2.(jvm 静态内部类只装载一次)和懒加载 推荐的
class Singleton{
private Singleton(){}
public static Singleton getInstance(){
return SingletonStatic.instance.;
}
private static class SingletonStatic{
private final static Singleton instance=new Singleton();
}
8.枚举(内置的成员可以创建对象) jdk1.5添加枚举实现单例模式 优点:线程安全,复制反序列化重新创建对象(effective java的josh bloch) 推荐使用
enum ENUMSINGLE8{
INSTANCE,INSTANCE1;;
public void play(){
System.out.println("快和妲己一起玩耍");
}
}
class hh{
public static void main(String[] args) {
//简单验证线程不安全
CopyOnWriteArrayList list = new CopyOnWriteArrayList();
for (int i = 1; i <=2000; i++) {
new Thread(()->{
ENUMSINGLE8 instance = ENUMSINGLE8.INSTANCE1;
instance.play();
list.add(instance.hashCode());
}).start();
}
while (Thread.activeCount()>2){
Thread.yield();
}
System.out.println(list);
}
}
3.jdk里的单例模式
1.RunTime类 饿汉式
2.使用场景 ,用于对象需要频繁(重量级对象)(耗时高)创建和销毁,检查使用的对象 工具类对象,频繁访问数据库或文件的对象(数据源或session工厂)
4.简单(静态)工厂模式(在工厂模式用得最多的,再加个静态方法setFactory)
- 传统方式 pizza制作过程和消费 写个Pizza类和抽象类,继承了抽象类,需要修改Pizza类 创建哪种pizza种类、
//改进后 图11简单工厂的传统方式实现
- 概念
1.是由一个过程对象创建出哪一种产品类的实例
2.封装实例化哪个对象的行为
3.大量创建某种类或某批对象时使用(批量生产对象)
图12简单工厂之改进方式实现
-----完整代码(自己不看代码,按思路敲出来,再对比别人的代码,受益匪浅…)—
//先创建Piza抽象类
public abstract class Pizza {
private String name;//披萨的名字
//披萨的操作
//准备披萨的材料不同,我们在设计的时候要考虑多种情况
// in fact,we have to define operation to all func(ensuring the function can not be alter)
public abstract void prepare();
public void cut(){
System.out.println("cut");
}
public void bake(){
System.out.println("bake");
}
//打包
public void pack(){
System.out.println("pack");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//创建他的子类
public class ChinesePiza extends Pizza{
@Override
public void prepare() {
System.out.println(super.getName()+"chinese piza prepare");
}
}
//创建他的另外一个子类
public class PepperPiza extends Pizza{
@Override
public void prepare() {
System.out.println("pepper piza prepare");
}
}
//(核心步骤)创建简单工厂类,专门创建对象,不要加入其他功能
public class PizaSimpleFactory {
static Pizza pizza=null;
public static Pizza createPiza(String type){
if(type.equals("chinese")){
pizza = new ChinesePiza();
pizza.setName("中国披萨");
return pizza;
}else if(type.equals("pepper")){
pizza = new PepperPiza();
pizza.setName("中国披萨");
return pizza;
}
return pizza;
}
}
//下单才调用处理业务,相当于 三层架构的 service,调用工厂创建对象
public class OrderPiza {
void doOrder(String type){
Pizza piza = PizaSimpleFactory.createPiza(type);
if (piza!=null){
piza.prepare();
piza.bake();
piza.cut();
piza.pack();
}else {
System.out.println("创建披萨订单失败");
}
}
}
//相当于controller,调用创建订单
public class PizaController {
public static void main(String[] args) {
OrderPiza orderPiza = new OrderPiza();
orderPiza.doOrder("pepper");
}
}
5.工厂方法模式(对简单工厂创建类保存抽象类,到子类实现具体的功能)(现在有了具体的披萨如北京胡椒披萨)
//就是大工厂创建 对象 后小工厂创建 更小的更具体的对象
图 13工厂方法模式
//BJcheessPizza事实上是一个工厂子类 //核心代码,是工厂类和子工厂 //工厂类
public class AllKindOfPizzaFactory {
public Pizza createPizza(String type) {
Scanner scanner = new Scanner(System.in);
System.out.println("输入你要的具体披萨类型");
String typeDetail = scanner.next();
if (type.equals("bj")) {
BJOrderPiza bjOrderPiza = new BJOrderPiza();
return bjOrderPiza.createPizza(typeDetail);
} else if (type.equals("ld")) {
LDOrderPiza ldOrderPiza = new LDOrderPiza();
return ldOrderPiza.createPizza(typeDetail);
}
return null;
}
}
//子工厂1继承大工厂
public class BJOrderPiza extends AllKindOfPizzaFactory {
Pizza pizza;
//违反了ocp原则
public Pizza createPizza(String type){
if(type.equals("chinese")){
pizza = new BJChinesePiza();
pizza.setName("北京中国披萨");
return pizza;
}else if(type.equals("pepper")){
pizza = new BJPepperPiza();
pizza.setName("北京胡椒披萨");
return pizza;
}
return pizza;
}
}
//子工厂2继承大工厂
public class LDOrderPiza extends AllKindOfPizzaFactory {
Pizza pizza;
//违反了ocp原则
public Pizza createPizza(String type){
if(type.equals("chinese")){
pizza = new LDChinesePiza();
pizza.setName("伦敦中国披萨");
return pizza;
}else if(type.equals("ld")){
pizza = new LDPepperPiza();
pizza.setName("伦敦胡椒披萨");
return pizza;
}
return pizza;
}
}
//抽象实体类
public abstract class Pizza {
private String name;//披萨的名字
//披萨的操作
//准备披萨的材料不同,我们在设计的时候要考虑多种情况
// in fact,we have to define operation to all func(ensuring the function can not be alter)
public abstract void prepare();
public void cut(){
System.out.println("cut");
}
public void bake(){
System.out.println("bake");
}
//打包
public void pack(){
System.out.println("pack");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//抽象实体类的子类1
public class LDPepperPiza extends Pizza {
@Override
public void prepare() {
System.out.println("ldpepper piza prepare");
}
}
//抽象实体类的子类2
public class BJPepperPiza extends Pizza {
@Override
public void prepare() {
System.out.println("ldpepper piza prepare");
}
}
public class OrderPizza {
void doPizaOrder(String type){
AllKindOfPizzaFactory orderPizzaFactory = new AllKindOfPizzaFactory();
Pizza pizza = orderPizzaFactory.createPizza(type);
if(pizza!=null){
pizza.prepare();
pizza.cut();
pizza.bake();
pizza.pack();
}else {
System.out.println("披萨不存在");
}
}
}
//client调用
public class PizaaController {
public static void main(String[] args) {
OrderPizza orderPizza = new OrderPizza();
orderPizza.doPizaOrder("bj");
}
}
6.抽象工厂(简单+工厂方法) 写一个接口抽象最大的工厂
//如图14抽象工厂模式
//核心代码 抽象接口的工厂类
public interface AbsFactory {
//让下面的工厂子类来 具体实现
public Pizza createPizza(String orderType);
}
//抽象工厂的子工厂
public class BJFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("~使用的是抽象工厂模式~");
// TODO Auto-generated method stub
Pizza pizza = null;
if(orderType.equals("cheese")) {
pizza = new BJChinesePiza();
} else if (orderType.equals("pepper")){
pizza = new BJPepperPiza();
}
return pizza;
}
}
public class LDFactory implements AbsFactory {
@Override
public Pizza createPizza(String orderType) {
System.out.println("~使用的是抽象工厂模式~");
Pizza pizza = null;
if (orderType.equals("chinese")) {
pizza = new LDChinesePiza();
} else if (orderType.equals("pepper")) {
pizza = new LDPepperPiza();
}
return pizza;
}
}
//下单类聚合工厂
public class OrderPizza {
AbsFactory factory;
// 构造器
public OrderPizza(AbsFactory factory) {
setFactory(factory);
}
private void setFactory(AbsFactory factory) {
Pizza pizza = null;
String orderType = ""; // 用户输入
this.factory = factory;
do {
orderType = getType();
// factory 可能是北京的工厂子类,也可能是伦敦的工厂子类
pizza = factory.createPizza(orderType);
if (pizza != null) { // 订购ok
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println("订购失败");
break;
}
} while (true);
}
// 写一个方法,可以获取客户希望订购的披萨种类
private String getType() {
try {
BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
System.out.println("input pizza 种类:");
String str = strin.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
//调用创建订单测试类
public class PizzaStore {
public static void main(String[] args) {
// TODO Auto-generated method stub
//new OrderPizza(new BJFactory());
new OrderPizza(new LDFactory());
}
}
7.使用简单工厂的jdk Calendar类里的getInstance方法的createCalendar方法 的switch case工厂不一定是要有 factory命名的,只要看到批量出现new关键字可能是工厂模式
//要依赖抽象(不要依赖具体实现的类) ,下面是源代码
public static Calendar getInstance(TimeZone zone)
{
return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
}
public static Calendar getInstance(Locale aLocale)
{
return createCalendar(TimeZone.getDefault(), aLocale);
}
/**
* Gets a calendar with the specified time zone and locale.
* The <code>Calendar</code> returned is based on the current time
* in the given time zone with the given locale.
*
* @param zone the time zone to use
* @param aLocale the locale for the week data
* @return a Calendar.
*/
public static Calendar getInstance(TimeZone zone,
Locale aLocale)
{
return createCalendar(zone, aLocale);
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) { //批量创建
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
8.原型模式prototype(对象的复制)(如果要复制一个对象的所有信息给其他对象,必须一一赋值他的信息 效率低) 大圣拔毛A变出多个大圣
如原理图 15原型类uml原理图
//克隆羊案例(写一个羊的实体类,在测试方法new 一个羊,其他羊复制他的信息)传统浅拷贝写法
//java使用 类实现 Cloneable 覆盖Object的clone()方法???
protected Object clone(){
Sheep sheep=null; //如果羊没有被创建不能被克隆
sheep=(Sheep)super.clone();
return sheep;
}
//使用,如果修改属性 不会修改代码,对比对象不是同一个
Sheep sheep=new Sheep("tom","黑色")
Sheep sheep1=(Sheep)sheep.clone();
9.原型模式
缺点: 每个类必须配备一个克隆方法,但是对已有类修改违反了ocp原则
//如果羊类里面有个羊(朋友)的对象会不会拷贝? 会,但是指向原来类的赋值的对象(浅拷贝) hashcode一样的
//传统方案实现
public class testA {
public static void main(String[] args) {
//Sheep的朋友还是属于一个同一个hashcode,所以是浅拷贝
Sheep sheep = new Sheep("tom",11);
sheep.setFriend(new Sheep("aa",11));
Sheep friend = sheep.getFriend();
System.out.println(friend.hashCode());
Sheep sheep1 = new Sheep(sheep.getName(),sheep.getAge());
sheep1.setFriend(new Sheep("aa",11));
System.out.println(sheep.getFriend().hashCode());
System.out.println(sheep);
System.out.println(sheep1);
}
}
//深拷贝, 要对他的所有成员进行拷贝,是引用类型的话要创建新空间进行拷贝
//实现方法1 实现 Cloneable 重写克隆方法,得到类的成员对象单独处理
protected Object clone(){
Sheep sheep=null; //如果羊没有被创建不能被克隆
//对基本数据类型和String进行拷贝
//对引用类型单独处理,调用引用类型的clone方法
//子类hashcode和复制的对象的不一样
sheep=(Sheep)super.clone();
try{ //必须需要,因为会递归调用,不然报空指针
sheep.friend=(Sheep)sheep.friend.clone();
}catch (Exception e){
System.out.println(e.getMessage());
}
return sheep;
}
//方式2(推荐使用) 实现 Serializable 使用对象序列化和反序列化(使用对象流) 可以批量处理成员对象
-----完整代码------
public class Sheep implements Cloneable, Serializable {
private String name;
private Integer age;
private Sheep friend;
public Sheep(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
//方式1 需要Cloneable
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep=null;
sheep=(Sheep)super.clone();
System.out.println("aa"+sheep);
try{
sheep.friend=(Sheep)friend.clone();
}catch (Exception e){
System.out.println(e.getMessage());
}
return sheep;
}
//方式2 需要Serializable
public Sheep copyObject() {
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化,对象变成二进制流,通过对象流写入
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出
//反序列化,把二进制变成变成对象流
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
Sheep copyObj = (Sheep) ois.readObject();
return copyObj;
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
// TODO: handle exception
System.out.println(e2.getMessage());
}
}
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", friend=" + friend +
'}';
}
}
-----测试------
public class testB {
public static void main(String[] args) throws CloneNotSupportedException {
//方式1
Sheep sheep = new Sheep("tom",11);
sheep.setFriend(new Sheep("jerry",12));
Sheep friend1 = sheep.getFriend();
System.out.println("复制前"+friend1.hashCode());
Sheep clone = (Sheep) sheep.clone();
Sheep friend = clone.getFriend();
System.out.println("复制后"+friend.hashCode());
//测试方式二
System.out.println("方式2--------------");
Sheep sheep3 = new Sheep("tom",12);
sheep3.setFriend(new Sheep("jerry",12));
System.out.println(sheep3);
System.out.println(sheep3.hashCode());
Sheep friend2 = sheep3.getFriend();
System.out.println(friend2.hashCode());
System.out.println(sheep3.hashCode());
Sheep sheep4 = sheep3.copyObject();
System.out.println(sheep4);
System.out.println(sheep4.hashCode());
Sheep friend3 = sheep4.getFriend();
System.out.println(friend3.hashCode());
System.out.println(sheep4.hashCode());
}
}
10.原型模式 spring代码创建bean(beans.xml里面的定义bean的scope=“prototype”) 和getbean判断是否为原型对象
//代码 beans.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 这里我们的 scope="prototype" 即 原型模式来创建 -->
<bean id="id01" class="com.atguigu.spring.bean.Monster"
scope="prototype"/>
</beans>
//getBean方法
public class ProtoType {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// 获取monster[通过id获取monster]
Object bean = applicationContext.getBean("id01");
System.out.println("bean" + bean); // 输出 "牛魔王" .....
Object bean2 = applicationContext.getBean("id01");
System.out.println("bean2" + bean2); //输出 "牛魔王" .....
System.out.println(bean == bean2); // false
// ConfigurableApplicationContext
}
}
//追到AbstactApplicationContext的getBean
public Object getBean(String name) throws BeansException {
this.assertBeanFactoryActive();
return this.getBeanFactory().getBean(name);
}
进入this.getBeanFactory().getBean(name); 方法的AbstractBeanFactory类 的this.doGetBean
具体实现有 } else if (mbd.isPrototype()) { //会去创建一个hashcode不一样的对象,getBean每次得到了不同的对象
11.建造者模式(builder)(生成器模式)
什么是?
1.有固定步骤的但是过程不同可以用
2.4个角色 Product(产品角色) Builder(抽象建造者) ConcreteBuilder(具体建造者) Director(指挥者) 构造一个Builder接口的对象(调用抽象建造过程)
图 16建造者模式原理图解决了什么? 加了抽象类做个缓冲层, 产品和产品建筑过程解耦
怎么做? 建房子例子
//传统方式 实体类和建造过程耦合度高
public abstract class House {
private String name;
private Integer age;
public abstract void base();
public abstract void block();
public abstract void roofed();
public void build(){
this.base();
this.block();
this.roofed();
}
}
public class NormalHouse extends House{
@Override
public void base() {
System.out.println("普通打地基");
}
@Override
public void block() {
System.out.println("普通砌10cm砖块");
}
@Override
public void roofed() {
System.out.println("普通盖屋顶");
}
}
//测试,要增加一个其他类型的楼房,需要再次继承 所有成员和成员方法
public class TestBuildClient {
public static void main(String[] args) {
NormalHouse normalHouse = new NormalHouse();
normalHouse.build();
}
}
//改进方式 图 17.建造者模式代码实现
//创建没有方法的成员实体
public class House {
private String name;
private Integer age;
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "House{" +
"name='" + name + '\'' +
", age=" + age +
", type='" + type + '\'' +
'}';
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
//2.创建builder抽象类专门来写 创建过程,并且聚合实体
public abstract class HouseBuilder {
protected House house=new House();
public abstract void base();
public abstract void block();
public abstract void roofed();
public House build(){
return house;
};
}
//3.创建他的子类 实现方法并且可以操作实体的成员
public class ModernHouse extends HouseBuilder {
@Override
public void base() {
this.house.setType("摩天大楼"); //自己可以操作实体成员
System.out.println("摩天大楼打地基");
}
@Override
public void block() {
System.out.println("摩天大楼砌20cm砖块");
}
@Override
public void roofed() {
System.out.println("摩天大楼盖透明屋顶");
}
}
//4.创建指挥者调用全部 的创建过程,构造方法传入要构造房子的类型
public class HouseDirector {
HouseBuilder houseBuilder;
HouseDirector(HouseBuilder houseBuilder){
this.houseBuilder=houseBuilder;
}
public void setHouseBuilder(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public House constructHouse(){
houseBuilder.base();
houseBuilder.block();;
houseBuilder.roofed();
return houseBuilder.build();
}
}
//Client使用 指挥者
public class Client {
public static void main(String[] args) {
HouseDirector houseDirector = new HouseDirector(new NormalHouse());
House house = houseDirector.constructHouse();
System.out.println(house);
HouseDirector houseDirector1 = new HouseDirector(new ModernHouse());
House house1 = houseDirector1.constructHouse();
System.out.println(house1);
}
}
12.jdk建造者StringBuilder(不是完全的建造者,jdk作者太强了,设计模式还没有出来,就有代码了)
的Appendable接口的多个append方法(抽象)(builder)
AbstractStringBuilder实现了Appendable方法,不能实例化 (建造者)
StringBuilder充当了指挥者,也充当了具体的建造者
public class BuilderSourceCode {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("ngs");
stringBuilder.insert(0,"aaa");
System.out.println(stringBuilder);
}
}
//StringBuilder
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
//建造者 AbstractStringBuilder
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
13.建造者注意点
1.符合开闭原则
2.如果产品差异太大,不适合用
3.抽象工厂(是创建不同类的产品) 建造者(是相同产品,但是组装的不同步骤[蓝图])
14.适配器模式
- 是什么
1.(为了兼容性,类/接口转为另外一个类/接口)比如如果缺少参数不能调用, 电源适配器适配不同规格的插座
2.用户看不到适配者,是解耦的
3.几个角色 dist(目标)<-适配器Adapter<-src(source)被适配者
//没有适配器的代码
public class Phone {
Voltage5V v;
Phone(Voltage5V v){
this.v=v;
}
void charge(){
if(v.out5V()==5){
System.out.println("充电成功");
}else {
System.out.println("充电失败");
}
}
}
//220v类输出220v电压
public class Voltage220V {
int output(){
return 220;
}
}
//直接在5V转220V增加了耦合
//需要从220转为5v
public class Voltage5V {
Voltage220V v;
Voltage5V(Voltage220V v){
this.v=v;
}
int out5V(){
if (v.output()==220){
int out5=v.output()/44;
return out5;
}
return 0;
}
}
//这里我觉得我把charge方法传入电压比较合适,不然每次使用手机都要传入充电的对象
public class testPhone {
public static void main(String[] args) {
Voltage5V voltage5V = new Voltage5V(new Voltage220V()); //这里同时看到220v和5v类
Phone phone = new Phone(voltage5V);
phone.charge();
}
}
2.类适配器(继承 类方式给到) 图18类适配器
- 需要继承src类(尽量不用继承),dst必须是接口
- src类的方法在Adapter使用,增加了使用成本
- adapter类继承src类可以重写方法,提高了灵活性
//手机类
public class Phone {
void charge(IVoltage5V v){
if(v.output5V()==5){
System.out.println("充电成功");
}else {
System.out.println("充电失败");
}
}
}
//220v类输出220v电压
public class Voltage220V {
int output220V(){
return 220;
}
}
//引发了一个思考,220v类是具体的,5v是接口抽象的(因为他可以通过220v转换过来,所以不用写,让适配器类去实现代码)
public interface IVoltage5V {
public int output5V();
}
//适配器类,主要继承和实现两个功能,相当于合并类的功能
public class IVoltage5VAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
int out=output220V()/44;
if (out==5){
return 5;
}
return 0;
}
}
//测试
public class Client {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charge(new IVoltage5VAdapter()); //客户端看不到220这个类了,就是解耦了
}
}
3.对象适配器(对象方式给到适配器)(类适配器改继承为聚合关系,记得对象判空) uml图 19对象适配器
//类适配器代码的基础上,改适配器类继承为聚合
//适配器类,主要继承和实现两个功能,相当于合并功能
public class IVoltage5VAdapter implements IVoltage5V { //去继承,继承违反里氏定律
Voltage220V v;//改继承为聚合关系
IVoltage5VAdapter(Voltage220V v){
this.v=v;
}
@Override
public int output5V() {
int dist=0;
System.out.println(v);
if (null!=v){ //必须进行判空,以免聚合的对象不存在
dist=v.output220V()/44;
if (dist==5){
return dist;
}
}
return dist;
}
}
//改测试代码
public class Client {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charge(new IVoltage5VAdapter(new Voltage220V()));
}
}
4.接口(缺省)适配器模式(实现)(抽象类实现接口空实现)(不想实现接口的全部方法,抽象类空实现方法,使用匿名内部类重写)
图 20接口适配器
//假设我们这个手机是快充的,可以适配很多个 5v 7v 20v电压的
public class Phone {
void charge(IVoltageAny v){
if(v.output5V()==5){
System.out.println("充电成功"+v.output5V()+"V");
}else if(v.output7V()==7){
System.out.println("充电成功"+v.output7V()+"V");
}else if(v.output20V()==20){
System.out.println("充电成功"+v.output20V()+"V");
}else {
System.out.println(v.output5V());
System.out.println("充电失败");
}
}
}
//220v类输出220v电压
public class Voltage220V {
int output220V(){
return 220;
}
}
//转换任何类型的电压
public interface IVoltageAny {
public int output5V();
public int output7V();
public int output20V();
}
//抽象类可以空实现后覆盖
public abstract class IVoltageAdapter implements IVoltageAny {
@Override
public int output5V() {
return 0;
}
@Override
public int output7V() {
return 0;
}
@Override
public int output20V() {
return 0;
}
}
//覆盖空实现
public class Client {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charge(new IVoltageAdapter() {
@Override
public int output5V() {
int dist=0;
Voltage220V voltage220V = new Voltage220V();
if (null!=voltage220V){
dist=voltage220V.output220V()/44;
if (dist==5){
return dist;
}
}
return dist;
}
});
phone.charge(new IVoltageAdapter() {
@Override
public int output20V() {
int dist=0;
Voltage220V voltage220V = new Voltage220V();
if (null!=voltage220V){
dist=voltage220V.output220V()/11;
if (dist==20){
return dist;
}
}
return dist;
}
});
}
}
15.springmvc的接口适配器 DispatchServlet类的HandlerAdapter
图21适配器springmvc源代码
//源代码片段,适配器是通过判断String然后getBean得到controller的
//DispatchServlet类
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!核心代码
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
//核心代码的得到适配器方法 的supports方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
//适配器接口
public interface HandlerAdapter {
//最后修改的handler
long getLastModified(HttpServletRequest request, Object handler);
}
//手写模拟源代码运行过程
1.写Controller接口和不同实现类(空实现因为具有语义化) 来处理请求
//多种Controller实现
public interface Controller {
}
class HttpController implements Controller {
public void doHttpHandler() {
System.out.println("http...");
}
}
class SimpleController implements Controller {
public void doSimplerHandler() {
System.out.println("simple...");
}
}
class AnnotationController implements Controller {
public void doAnnotationHandler() {
System.out.println("annotation...");
}
}
2.写适配器接口和他们的实现类(有、support适配方法和handle处理请求方法)
///定义一个Adapter接口
public interface HandlerAdapter {
public boolean supports(Object handler);
public void handle(Object handler);
}
// 多种适配器类
class SimpleHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((SimpleController) handler).doSimplerHandler();
}
public boolean supports(Object handler) {
return (handler instanceof SimpleController);
}
}
class HttpHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((HttpController) handler).doHttpHandler();
}
public boolean supports(Object handler) {
return (handler instanceof HttpController);
}
}
class AnnotationHandlerAdapter implements HandlerAdapter {
public void handle(Object handler) {
((AnnotationController) handler).doAnnotationHandler();
}
public boolean supports(Object handler) {
return (handler instanceof AnnotationController);
}
}
3.创建一个List放适配器类,
doDispatch调用适配器方法getHandler的supports方法使用instanceof 判断传入controller是否是controller对象的实例,返回转换的controller的调用doHttpHandler的结果
public class DispatchServlet {
public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();
public DispatchServlet() {
handlerAdapters.add(new AnnotationHandlerAdapter());
handlerAdapters.add(new HttpHandlerAdapter());
handlerAdapters.add(new SimpleHandlerAdapter());
}
public void doDispatch() {
// 此处模拟SpringMVC从request取handler的对象,
// 适配器可以获取到希望的Controller
HttpController controller = new HttpController();
// AnnotationController controller = new AnnotationController();
//SimpleController controller = new SimpleController();
// 得到对应适配器
HandlerAdapter adapter = getHandler(controller);
// 通过适配器执行对应的controller对应方法
adapter.handle(controller);
}
public HandlerAdapter getHandler(Controller controller) {
//遍历:根据得到的controller(handler), 返回对应适配器
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(controller)) {
return adapter;
}
}
return null;
}
public static void main(String[] args) {
new DispatchServlet().doDispatch(); // http...
}
}
//思考我直接调用controller的方法不就好了,为什么还要脱裤子放屁?
//答案: 1.主要是为了软件的长远增加代码考虑,如果增加多几个controller,岂不是要增加几个判断条件判断是哪个controller然后调用使代码复杂 不好维护
//2.这样做直接 add适配器类,不用改依赖的代码,增加一个controller和adapter(这是写代码的套路)
public DispatchServlet() {
handlerAdapters.add(new AnnotationHandlerAdapter());
handlerAdapters.add(new HttpHandlerAdapter());
handlerAdapters.add(new SimpleHandlerAdapter());
handlerAdapters.add(new XXXAdapter());
}