wordpress门户网站主题,佳木斯做网站公司,现货做网站,wordpress怎么添加图片不显示图片Java设计模式笔记#xff08;一#xff09;
#xff08;23种设计模式由于篇幅较大分为两篇展示#xff09;
一、设计模式介绍
1、设计模式的目的
让程序具有更好的#xff1a;
代码重用性可读性可扩展性可靠性高内聚#xff0c;低耦合
2、设计模式的七大原则 单一职…Java设计模式笔记一
23种设计模式由于篇幅较大分为两篇展示
一、设计模式介绍
1、设计模式的目的
让程序具有更好的
代码重用性可读性可扩展性可靠性高内聚低耦合
2、设计模式的七大原则 单一职责原则 一个类只负责一项职责,降低类的复杂度提高类的可读性和可维护性降低变更引起的风险 接口隔离原则 一个类对另一个类的依赖应该建立在最小接口上 上述图片类A只需要接口中的1方法但是却要实现2345方法这就违背了最小接口原则对其进行改进 对接口拆分成几个独立的接口采用接口隔离原则 依赖倒置原则 高层模块不应该依赖底层模块二者都应该依赖其抽象 抽象不应该依赖细节细节应该依赖抽象 依赖倒转(倒置)的中心思想是面向接口编程 使用接口或抽象类的目的是制定好规范而不涉及任何具体的操作把展现细节的任务交给他们的实现类去完成 如图所示 如果之后有个短信业务则需要再person中在加个短信的业务对其进行改进 引入接口IReceiverPerson类与接口IReceiver发生依赖关系及时之后又短信业务也只需要实现IReceiver接口即可。 里氏替换原则 继承性说明 父类中凡是已经实现好的方法实际上是在设定规范和契约虽然它不强制要求所有的子类必须遵循这些契约但是如果子类对这些已经实现的方法任意修改就会对整个继承体系造成破坏。 继承性弊端 使用继承会给程序带来侵入性,程序的可移植性降低增加对象间的耦合性如果一个类被其他的类所继承则当这个类需要修改时必须考虑到所有的子类并且父类修改后所有涉及到子类的功能都有可能产生 介绍 简单说就是所有引用基类的地方必须透明的使用其子类的对象。 在继承时子类中尽量不要重写父类中的方法 上图中父类中的add方法是ab但是子类B重写了父类的add方法将其改为了a-b当程序调用的时候可能会出现错误。 采用依赖、聚合、组合的方法替换抽取一个共同的父类在使用C的时候还可使用B的原始方法。 1、创建一个基类 class Base {}2、A类 class A extends Base {public int fun1(int a, int b) {return ab;}
}3、B类 class B extends Base {private A a new A();// 写自己的方法public int fun1(int a, int b) {return ab;}// 仍然使用A的方法public int fun2(int a, int b) {return this.a.fun1(a,b);}
}开闭原则 是编程中最基础、最重要的设计原则当软件需要修改时尽量通过扩展软件实体的行为来实现变化而不是通过修改已有的代码来实现变化。 代码演示: //这是一个用于绘图的类
class GraphicEditor {//接收 Shape 对象然后根据 type来绘制不同的图形public void drawShape(Shape s){if(s.m_type-1)drawRectangle(s);else if(s.m type-2)drawCircle(s);else if(s.m_type - 3)drawTriangle(s)}//绘制矩形public void drawRectangle(Shape r){System.out.printn(”绘制矩形);}//绘制圆形public void drawCircle(Shape r){System.out.println(绘制圆形);}//绘制三角形public void drawTriangle(Shape r){System.out.println(”绘制三角形);}
}//Shape 类基类
class Shape {int m_type;
}class Rectangle extends Shape {Rectangle(){super.m_type1;}
}class Circle extends Shape {Circle() {super.m_type 2;}
}//新增画三角形
class Triangle extends Shape {Triangle() {super.m_type 3;}
}// 开始调用
public class Ocp {public static void main(Stringll args){//使用看看存在的问题GraphicEditor graphicEditor new GraphicEditor();graphicEditor.drawShape(new Rectangle());graphicEditor.drawShape(new Circle());graphicEditor.drawShape(new Triangle());}
}上述代码的优缺点 1、比较好理解 2、缺点就是违反了设计模式的ocp原则。即对扩展开放对修改关闭当要新增功能时GraphicEditor需要做修改。 改进 把创建 Shape 类做成抽象类并提供一个抽象的 draw方法让子类去实现即可这样我们有新的图形种类时只需要让新的图形类继承 Shape并实现 draw方法即可使用方的代码就不需要修 - 满足了开闭原则 //这是一个用于绘图的类
class GraphicEditor {//接收 Shape 对象调用draw方法public void drawShape(Shape s){s.draw();}
}//Shape 类基类
abstract class Shape {int m_type;public abstract void draw();//抽象方法
}class Rectangle extends Shape {Rectangle(){super.m_type1;}Overridepublic void draw(){// TODO Auto-generated method stubSystem.out.println(绘制矩形);}
}class Circle extends Shape {Circle() {super.m_type 2;}Overridepublic void draw(){// TODO Auto-generated method stubSystem.out.println(绘制圆形);}
}//新增画三角形
class Triangle extends Shape {Triangle() {super.m_type 3;}Overridepublic void draw(){// TODO Auto-generated method stubSystem.out.println(绘制三角形);}
}// 开始调用
public class Ocp {public static void main(Stringll args){//使用看看存在的问题GraphicEditor graphicEditor new GraphicEditor();graphicEditor.drawShape(new Rectangle());graphicEditor.drawShape(new Circle());graphicEditor.drawShape(new Triangle());}
}迪米特法则 迪米特法则(Demeter Principle)又叫最少知道原则即一个类对自己依赖的类知道的越少越好。也就是说对于被依赖的类不管多么复杂都尽量将逻辑封装在类的内部。对外除了提供的 public 方法不对外泄露任何信息。 合成复用原则 尽量使用合成/聚合的方式而不是使用继承
二、设计模式概述
1、介绍
设计模式是程序员在面对同类软件工程设计问题所总结出来的有用的经验模式不是代码而是某类问题的通用解决方案设计模式(Design patern)代表了最佳的实践。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。 设计模式的本质提高软件的维护性通用性和扩展性并降低软件的复杂度
2、设计模式类型
设计模式分为三种类型共 23种
1创建型模式单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
2结构型模式适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
3行为型模式模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式.解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)。
三、单例设计模式
1、介绍
所谓类的单例设计模式就是采取一定的方法保证在整个的软件系统中对某个类只能存在一个对象实例并且该类只提供一个取得其对象实例的方法(静态方法)。
2、单例模式的8种方式
饿汉式(静态常量)饿汉式(静态代码块)懒汉式(线程不安全)懒汉式(线程安全同步方法)懒汉式(线程安全同步代码块)双重检查静态内部类枚举
1饿汉式静态常量
实现步骤 构造器私有化(防止 new ) 类的内部创建对象 向外暴露一个静态的公共方法。getlnstance 代码实现
//饿汉式(静态变量)
class Singleton {//1.构造器私有化外部能 newprivate Singleton() {}//2.本类内部创建对象实例private final static Singleton instance new Singleton().//3.提供一个公有的静态方法返回实例对象public static Singleton getInstance(){return instance;}
}public class SingletonTest {public static void main(String|largs){//测试Singleton instance Singleton.getInstance();Singleton instance2 Singleton.getInstance();System.out.println(instance instance2); // trueSystem.out.println(instance.hashCode instance .hashCode());System.out.println(instance2.hashCode instance2.hashCode()):}
}说明
1优点这种写法比较简单就是在类装载的时候就完成实例化。避免了线程同步问题。
2缺点在类装载的时候就完成实例化没有达到LazyLoading 的效果。如果从始至终从未使用过这个实例则 会造成内存的浪费
3这种方式基于 classloder 机制避免了多线程的同步问题不过instance 在类装载时就实例化在单例模式中大多数都是调用 getnstance方法但是导致类装载的原因有很多种因此不能确定有其他的方式(或者其他的静态方法)导致类装载这时候初始化instance 就没有达到 lazy loading 的效果
2饿汉式静态代码块
public class Singleton {//1.构造器私有化外部能 newprivate Singleton(){}//2.本类内部创建实例对象private static Singleton instance;//3. 在静态代码块中创建单例对象static {instance new Singleton();}// 4.提供一个公有的静态方法返回实例对象public static Singleton getInstance (){return instance;}}说明
1这种方式和上面的方式其实类似只不过将类实例化的过程放在了静态代码块中也是在类装载的时候就执行静态代码块中的代码初始化类的实例。优缺点和上面是一样的。
2这种单例模式可用但是可能造成内存浪费
3懒汉式线程不安全
public class Singleton {//1.构造器私有化外部能 newprivate Singleton(){}//2.本类内部创建实例对象private static Singleton instance;//3. 提供一个静态公有方法当使用到该方法时才去创建instancepublic static Singleton getInstance (){if (instance null) {instance new Singleton();}return instance;}}说明
1起到了 Lazy Loading的效果但是只能在单线程下使用。
2如果在多线程下一个线程进入了 if(singleton nul)判断语句块还未来得及往下执行另一个线程也通过了这个判断语句这时便会产生多个实例。所以在多线程环境下不可使用这种方式
3在实际开发中不要使用这种方式
4懒汉式线程安全同步方法
public class Singleton {//1.构造器私有化外部能 newprivate Singleton(){}//2.本类内部创建实例对象private static Singleton instance;//3. 提供一个静态公有方法加synchronized关键词保证线安全当使用到该方法时才去创建instancepublic static synchronized Singleton getInstance (){if (instance null) {instance new Singleton();}return instance;}}说明
1解决了线程安全问题
2效率太低了每个线程在想获得类的实例时候执行 getinstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了后面的想获得该类实例直接retumn 就行了。方法进行同步效率太低
3在实际开发中不推荐使用这种方式
5懒汉式线程安全同步代码块
public class Singleton {//1.构造器私有化外部能 newprivate Singleton(){}//2.本类内部创建实例对象private static Singleton instance;//3. 提供一个静态公有方法当使用到该方法时才去创建instancepublic static Singleton getInstance (){if (instance null) {// 添加同步代码块synchronized (Singleton.class) {instance new Singleton();}}return instance;}}不推荐使用
6双重检查
public class Singleton {//1.构造器私有化外部能 newprivate Singleton(){}//2.本类内部创建实例对象private static volatile Singleton instance;//3.提供一个静态的公有方法加入双重检査代码解决线程安全问题,同时解决懒加载问题,同同时保证了效率推荐使用public static Singleton getInstance (){if (instance null) {// 添加同步代码块synchronized (Singleton.class) {if (instance null) {instance new Singleton();}}}return instance;}}说明
1Double-Check概念是多线程开发中常使用到的如代码中所示我们进行了两次 if(singleton nul)检查这样就可以保证线程安全了。
2实例化代码只用执行一次后面再次访问时判断if(singleton null)直接retum 实例化对象也避免反复进行方法同步
3线程安全;延迟加载;效率较高
4在实际开发中推荐使用这种单例设计模式
7静态内部类
public class Singleton {//1.构造器私有化外部能 newprivate Singleton(){}//2.静态内部类private static class SingletonInstance {private static final Singleton INSTANCE new Singleton();}//3.提供一个静态的公有方法直接返回INSTANCE推荐使用public static Singleton getInstance (){return SingletonInstance.INSTANCE;}}说明
1这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
2静态内部类方式在 Singleton 类被装载时并不会立即实例化而是在需要实例化时调用 getnstance 方法才会装载 SingletonInstance 类从而完成 Singleton 的实例化。
3类的静态属性只会在第一次加载类的时候初始化所以在这里JVM 帮助我们保证了线程的安全性在类进行初始化时别的线程是无法进入的。
4避免了线程不安全利用静态内部类特点实现延迟加载效率高
5推荐使用
8枚举
// 枚举形式
public enum Singleton2 {INSTANCE;
}public static void main(String[] args) {Singleton2 instance Singleton2.INSTANCE;Singleton2 instance2 Singleton2.INSTANCE;System.out.println(instance instance2);System.out.println(instance.hashCode());System.out.println(instance2.hashCode());
}说明
1这借助JDK15 中添加的枚举来实现单例模式。不仅能避免多线程同步问题而且还能防止反序列化重新创建1)新的对象。
2这种方式是 Effective Java 作者 Josh Bloch 提倡的方式
3推荐使用
3、单例模式在jdk中的使用
java.lang.RunTime就是经典的单例恶汉模式 4、注意事项
1单例模式保证了 系统内存中该类只存在一个对象节省了系统资源对于一些需要频繁创建销毁的对象使用单例模式可以提高系统性能
2当想实例化一个单例类的时候必须要记住使用相应的获取对象的方法而不是使用 new
3单例模式使用的场景
需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象)但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等)
四、工厂模式
1、分类
简单工厂模式工厂方法模式抽象工厂模式
2、简单工厂模式
1介绍
1简单工厂模式是属于创建型模式是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
2简单工厂模式定义了一个创建对象的类由这个类来封装实例化对象的行为(代码)
3在软件开发中当我们会用到大量的创建某种类或者某批对象时就会使用到工厂模式
2案例
披萨的项目要便于披萨种类的扩展要便于维护
披萨的种类很多(比如 GreekPizz、CheesePizz 等)披萨的制作有 preparebake,cut, box完成披萨店订购功能。
1、创建一个pizza类
//将Pizza 类做成抽象
public abstract class Pizza {protected String name; //名字//准备原材料, 不同的披萨不一样因此我们做成抽象方法public abstract void prepare();public void bake() {System.out.println(name baking;);}public void cut() {System.out.println(name cutting;);}//打包public void box() {System.out.println(name boxing;);}public void setName(String name) {this.name name;}
}2、希腊披萨类
public class GreekPizza extends Pizza {Overridepublic void prepare() {// TODO Auto-generated method stubSystem.out.println(给【希腊披萨】准备原材料);}}3、奶酪pizza
public class CheesePizza extends Pizza {Overridepublic void prepare() {// TODO Auto-generated method stubSystem.out.println( 给制作奶酪披萨 准备原材料 );}}4、简单工厂类
public class SimpleFactory {//根据orderType 返回对应的Pizza 对象public Pizza createPizza(String orderType) {Pizza pizza null;System.out.println(使用简单工厂模式);if (orderType.equals(greek)){pizza new GreekPizza();pizza.setName( 希腊披萨 );} else if (orderType.equals(cheese)){pizza new CheesePizza();pizza.setName( 奶酪披萨 );}return pizza;}//简单工厂模式 也叫 静态工厂模式public static Pizza createPizza2(String orderType) {Pizza pizza null;System.out.println(使用简单工厂模式2);if (orderType.equals(greek)) {pizza new GreekPizza();pizza.setName( 希腊披萨 );} else if (orderType.equals(cheese)) {pizza new CheesePizza();pizza.setName( 奶酪披萨 );}return pizza;}
}
5、订购pizza
public class OrderPizza {//定义一个简单工厂对象SimpleFactory simpleFactory;Pizza pizza;String orderType;//构造器public OrderPizza(SimpleFactory simpleFactory, String orderType){this.simpleFactory simpleFactory;this.orderType orderType;setFactory();}private void setFactory() {// 根据用户输入的类型获取队形的pizza对象pizza simpleFactory.createPizza(orderType);//输出pizzaif(pizza ! null) { //订购成功pizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println( 订购披萨失败 );}}}6、测试 public static void main(String[] args) {//使用简单工厂模式new OrderPizza(new SimpleFactory(), greek);}
输出使用简单工厂模式
给【希腊披萨】准备原材料希腊披萨 baking;希腊披萨 cutting;希腊披萨 boxing; 如果之后需要增加pizza类型只需要在工厂中追加即可
3、工厂方法模式
1介绍
工厂方法模式定义了一个创建对象的抽象方法由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
2案例
披萨项目新的需求客户在点披萨时,可以点不同口味的披萨比如 北京的奶酪 pizza、北京的胡椒 pizza 或者是伦敦的奶酪 pizza、伦敦的胡椒 pizza 1、将Pizza 类做成抽象
//将Pizza 类做成抽象
public abstract class Pizza {protected String name; //名字//准备原材料, 不同的披萨不一样因此我们做成抽象方法public abstract void prepare();public void bake() {System.out.println(name baking;);}public void cut() {System.out.println(name cutting;);}//打包public void box() {System.out.println(name boxing;);}public void setName(String name) {this.name name;}
}2、北京奶酪pizza
public class BJCheesePizza extends Pizza {Overridepublic void prepare() {setName(北京的奶酪pizza);System.out.println( 北京的奶酪pizza 准备原材料);}}3、北京胡椒pizza
public class BJPepperPizza extends Pizza {Overridepublic void prepare() {// TODO Auto-generated method stubsetName(北京的胡椒pizza);System.out.println( 北京的胡椒pizza 准备原材料);}
}4、伦敦奶酪pizza
public class LDCheesePizza extends Pizza{Overridepublic void prepare() {// TODO Auto-generated method stubsetName(伦敦的奶酪pizza);System.out.println( 伦敦的奶酪pizza 准备原材料);}
}5、伦敦胡椒pizza
public class LDPepperPizza extends Pizza{Overridepublic void prepare() {// TODO Auto-generated method stubsetName(伦敦的胡椒pizza);System.out.println( 伦敦的胡椒pizza 准备原材料);}
}6、订购pizza抽象类
public abstract class OrderPizza {//定义一个抽象方法createPizza , 让各个工厂子类自己实现abstract Pizza createPizza(String orderType);// 构造器public OrderPizza(String orderType) {Pizza pizza createPizza(orderType); //抽象方法由工厂子类完成//输出pizza 制作过程pizza.prepare();pizza.bake();pizza.cut();pizza.box();}}7、订购北京pizza
public class BJOrderPizza extends OrderPizza {public BJOrderPizza(String orderType) {super(orderType);}OverridePizza createPizza(String orderType) {Pizza pizza null;if(orderType.equals(cheese)) {pizza new BJCheesePizza();} else if (orderType.equals(pepper)) {pizza new BJPepperPizza();}// TODO Auto-generated method stubreturn pizza;}}8、订购伦敦pizza
public class LDOrderPizza extends OrderPizza {public LDOrderPizza(String orderType) {super(orderType);}OverridePizza createPizza(String orderType) {Pizza pizza null;if(orderType.equals(cheese)) {pizza new LDCheesePizza();} else if (orderType.equals(pepper)) {pizza new LDPepperPizza();}// TODO Auto-generated method stubreturn pizza;}}9、测试 public static void main(String[] args) {new LDOrderPizza(cheese);}
// 伦敦的奶酪pizza 准备原材料
伦敦的奶酪pizza baking;
伦敦的奶酪pizza cutting;
伦敦的奶酪pizza boxing;说明
如果后期要加一个北京西红柿pizza只需要先实现Pizza抽象类可以写具体的实现过程再在BJOrderPizza类中加一个判断条件。
4、抽象工厂模式
1介绍
1抽象工厂模式定义了一个interface 用于创建相关或有依赖关系的对象簇而无需指明具体的类
2抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
3从设计层面看抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
4将工厂抽象成两层AbsFactory(抽象工厂)和 具体实现的工厂子类。根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇更利于代码的维护和扩展。 2案例
12345使用工厂方法模式代码
6、抽象工厂模式抽象层
//一个抽象工厂模式的抽象层(接口)
public interface AbsFactory {//让下面的工厂子类来 具体实现public Pizza createPizza(String orderType);
}7、北京工厂类
//这是工厂子类
public class BJFactory implements AbsFactory {public Pizza createPizza(String orderType) {System.out.println(~使用的是抽象工厂模式~);// TODO Auto-generated method stubPizza pizza null;if(orderType.equals(cheese)) {pizza new BJCheesePizza();} else if (orderType.equals(pepper)){pizza new BJPepperPizza();}return pizza;}
}8、伦敦工厂类
public class LDFactory implements AbsFactory {public Pizza createPizza(String orderType) {System.out.println(~使用的是抽象工厂模式~);Pizza pizza null;if (orderType.equals(cheese)) {pizza new LDCheesePizza();} else if (orderType.equals(pepper)) {pizza new LDPepperPizza();}return pizza;}}9、订购pizza类
public class OrderPizza {AbsFactory factory;// 构造器public OrderPizza(AbsFactory factory, String orderType) {setFactory(factory,orderType);}private void setFactory(AbsFactory factory, String orderType) {Pizza pizza null;this.factory factory;// factory 可能是北京的工厂子类也可能是伦敦的工厂子类pizza factory.createPizza(orderType);if (pizza ! null) { // 订购okpizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println(订购失败);}}}10、测试 public static void main(String[] args) {new OrderPizza(new BJFactory(), cheese);}
//
~使用的是抽象工厂模式~北京的奶酪pizza 准备原材料
北京的奶酪pizza baking;
北京的奶酪pizza cutting;
北京的奶酪pizza boxing;
5、总结
1将实例化对象的代码提取出来放到一个类中统一管理和维护达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。
2创建对象实例时不要直接 new 类,而是把这个 new 类的动作放在一个工厂的方法中并返回。
3不要让类继承具体类而是继承抽象类或者是实现interface(接口)不要覆盖基类中已经实现的方法。
五、原型模式
1、介绍
1原型模式(Prototype 模式)是指用原型实例指定创建对象的种类并且通过拷贝这些原型创建新的对象
2原型模式是一种创建型设计模式允许一个对象再创建另外一个可定制的对象无需知道如何创建的细节
3工作原理是将一个原型对象传给那个要发动创建的对象这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建即 对象.clone()
2、案例
基础类
public class Sheep implements Cloneable {private String name;private int age;private String color;public Sheep friend; //是对象, 克隆是会如何处理public Sheep(String name, int age, String color) {super();this.name name;this.age age;this.color color;}public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}public String getColor() {return color;}public void setColor(String color) {this.color color;}Overridepublic String toString() {return Sheep [name name , age age , color color ];}//克隆该实例使用默认的clone方法来完成Overrideprotected Object clone() {Sheep sheep null;try {sheep (Sheep)super.clone();} catch (Exception e) {// TODO: handle exceptionSystem.out.println(e.getMessage());}// TODO Auto-generated method stubreturn sheep;}}测试类 public static void main(String[] args) {Sheep sheep new Sheep(白羊, 5, 白色);sheep.friend new Sheep(jack, 2, 黑色);Sheep sheep1 (Sheep) sheep.clone();Sheep sheep2 (Sheep) sheep.clone();Sheep sheep3 (Sheep) sheep.clone();System.out.println(sheep1 friend-hash: sheep1.friend.hashCode());System.out.println(sheep2 friend-hash: sheep2.friend.hashCode());System.out.println(sheep3 friend-hash: sheep3.friend.hashCode());}输出
Sheep [name白羊, age5, color白色] friend-hash: 460141958 Sheep [name白羊, age5, color白色] friend-hash: 460141958 Sheep [name白羊, age5, color白色] friend-hash: 460141958
发现在克隆sheep时应用类型的friend只是做了浅拷贝
3、浅拷贝介绍
1对于数据类型是基本数据类型的成员变量浅拷贝会直接进行值传递也就是将该属性值复制一份给新的对象。
2对于数据类型是引用数据类型的成员变量比如说成员变量是某个数组、某个类的对象等那么浅拷贝会进行引用传递也就是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下在一个对象中修改该成员变量会影响到另一个对象的该成员变量值在上述案例中就是浅拷贝。
3浅拷贝是使用默认的 clone()方法来实现
sheep(Sheep) super.clone():
4、深拷贝介绍
1复制对象的所有基本数据类型的成员变量值
2为所有引用数据类型的成员变量申请存储空间并复制每个引用数据类型成员变量所引用的对象直到该对象可达的所有对象。也就是说对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝
3深拷贝实现方式 重写clone方法来实现深拷贝
4深拷贝实现方式通过对象序列化实现深拷贝(推荐)
5 案例
基本类型
public class DeepCloneableTarget implements Serializable, Cloneable {private static final long serialVersionUID 1L;private String cloneName;private String cloneClass;//构造器public DeepCloneableTarget(String cloneName, String cloneClass) {this.cloneName cloneName;this.cloneClass cloneClass;}//因为该类的属性都是String , 因此我们这里使用默认的clone完成即可Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}引用类型
public class DeepProtoType implements Serializable, Cloneable{public String name; //String 属性public DeepCloneableTarget deepCloneableTarget;// 引用类型public DeepProtoType() {super();}//深拷贝 - 方式 1 使用clone 方法// 缺陷如果引用类型属性的内部属性还是应用类型。则其内部的应用类型也要重写cloneOverrideprotected Object clone() throws CloneNotSupportedException {Object deep null;//这里完成对基本数据类型(属性)和String的克隆deep super.clone(); //对引用类型的属性进行单独处理DeepProtoType deepProtoType (DeepProtoType)deep;deepProtoType.deepCloneableTarget (DeepCloneableTarget)deepCloneableTarget.clone();// TODO Auto-generated method stubreturn deepProtoType;}//深拷贝 - 方式2 通过对象的序列化实现 (推荐)public Object deepClone() {//创建流对象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);DeepProtoType copyObj (DeepProtoType)ois.readObject();return copyObj;} catch (Exception e) {// TODO: handle exceptione.printStackTrace();return null;} finally {//关闭流try {bos.close();oos.close();bis.close();ois.close();} catch (Exception e2) {// TODO: handle exceptionSystem.out.println(e2.getMessage());}}}}测试 public static void main(String[] args) {// TODO Auto-generated method stubDeepProtoType p new DeepProtoType();p.name 李四;p.deepCloneableTarget new DeepCloneableTarget(大牛, 小牛);//方式2 完成深拷贝DeepProtoType p2 (DeepProtoType) p.deepClone();System.out.println(p.name p.name p.deepCloneableTarget p.deepCloneableTarget.hashCode());System.out.println(p2.name p.name p2.deepCloneableTarget p2.deepCloneableTarget.hashCode());}结果
p.name李四 p.deepCloneableTarget1836019240 p2.name李四 p2.deepCloneableTarget363771819
5、总结
1创建新的对象比较复杂时可以利用原型模式简化对象的创建过程同时也能够提高效率
2不用重新初始化对象而是动态地获得对象运行时的状态
3如果原始对象发生变化(增加或者减少属性)其它克隆对象的也会发生相应的变化无需修改代码
4在实现深克隆的时候可能需要比较复杂的代码
5缺点需要为每一个类配备一个克隆方法这对全新的类来说不是很难但对已有的类进行改造时需要修改其源代码违背了 ocp 原则。
六、建造者模式
1、介绍
1建造者模式(Builder Pattern) 又叫生成器模式是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别)使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
2建造者模式 是一步一步创建一个复杂的对象它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
2、四个角色
1Product(产品角色)一个具体的产品对象。
2Builder(抽象建造者)创建一个 Product 对象的各个部件指定的 接口/抽象类。
3ConcreteBuilder(具体建造者)实现接口构建和装配各个部件。
4Director(指挥者)构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用一是隔离了客户与对象的生产过程二是负责控制产品对象的生产过程。 3、案例
建房子需要打桩、砌墙、封顶等不管普通房、别墅都需要这个过程。 1、House类
//产品-Product
public class House {private String baise;private String wall;private String roofed;public String getBaise() {return baise;}public void setBaise(String baise) {this.baise baise;}public String getWall() {return wall;}public void setWall(String wall) {this.wall wall;}public String getRoofed() {return roofed;}public void setRoofed(String roofed) {this.roofed roofed;}}2、HouseBuilder抽象类
// 抽象的建造者
public abstract class HouseBuilder {protected House house new House();//将建造的流程写好, 抽象的方法public abstract void buildBasic();public abstract void buildWalls();public abstract void roofed();//建造房子好 将产品(房子) 返回public House buildHouse() {return house;}}3、CommonHouse类
public class CommonHouse extends HouseBuilder {Overridepublic void buildBasic() {// TODO Auto-generated method stubSystem.out.println( 普通房子打地基5米 );}Overridepublic void buildWalls() {// TODO Auto-generated method stubSystem.out.println( 普通房子砌墙10cm );}Overridepublic void roofed() {// TODO Auto-generated method stubSystem.out.println( 普通房子屋顶 );}}4、HighBuilding
public class HighBuilding extends HouseBuilder {Overridepublic void buildBasic() {// TODO Auto-generated method stubSystem.out.println( 高楼的打地基100米 );}Overridepublic void buildWalls() {// TODO Auto-generated method stubSystem.out.println( 高楼的砌墙20cm );}Overridepublic void roofed() {// TODO Auto-generated method stubSystem.out.println( 高楼的透明屋顶 );}}5、HouseDirector 类
public class HouseDirector {HouseBuilder houseBuilder null;//构造器传入 houseBuilderpublic HouseDirector(HouseBuilder houseBuilder) {this.houseBuilder houseBuilder;}//通过setter 传入 houseBuilderpublic void setHouseBuilder(HouseBuilder houseBuilder) {this.houseBuilder houseBuilder;}//如何处理建造房子的流程交给指挥者public House constructHouse() {houseBuilder.buildBasic();houseBuilder.buildWalls();houseBuilder.roofed();return houseBuilder.buildHouse();}}7、测试
public static void main(String[] args) {//盖普通房子CommonHouse commonHouse new CommonHouse();//准备创建房子的指挥者HouseDirector houseDirector new HouseDirector(commonHouse);//完成盖房子返回产品(普通房子)House house houseDirector.constructHouse();System.out.println(--------------------------);//盖高楼HighBuilding highBuilding new HighBuilding();//重置建造者houseDirector.setHouseBuilder(highBuilding);//完成盖房子返回产品(高楼)houseDirector.constructHouse();}输出
普通房子打地基5米 普通房子砌墙10cm 普通房子屋顶 高楼的打地基100米 高楼的砌墙20cm 高楼的透明屋顶
4、总结
1客户端(使用程序)不必知道产品内部组成的细节将产品本身与产品的创建过程解耦使得相同的创建过程可以创建不同的产品对象 2每一个具体建造者都相对独立而与其他的具体建造者无关因此可以很方便地替换具体建造者或增加新的具体建造者用户使用不同的具体建造者即可得到不同的产品对象
3可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中使得创建过程更加清晰, 也更方便使用程序来控制创建过程
4增加新的具体建造者无须修改原有类库的代码指挥者类针对抽象建造者类编程系统扩展方便符合“开闭原则”
5建造者模式所创建的产品一般具有较多的共同点其组成部分相似如果产品之间的差异性很大则不适合使用建造者模式因此其使用范围受到一定的限制。
6如果产品的内部变化复杂可能会导致需要定义很多具体建造者类来实现这种变化导致系统变得很庞大因此在这种情况下要考虑是否选择建造者模式。
7抽象工厂模式 VS 建造者模式 抽象工厂模式实现对产品家族的创建一个产品家族是这样的一系列产品具有不同分类维度的产品组合采用抽象工厂模式不需要关心构建过程只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品它的主要目的是通过组装零配件而产生一个新产品。
七、适配器模式
1、介绍
1适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示主的目的是兼容性让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)
2适配器模式属于结构型模式
3主要分为三类类适配器模式、对象适配器模式、接口适配器模式
2、类适配器模式
1介绍
Adapter 类通过继承 src 类实现 dst 类接口完成 src-dst 的适配
2案例
以生活中充电器的例子来讲解适配器充电器本身相当于 Adapter220V 交流电相当于 src (即被适配者)目的dst(即 目标)是 5V 直流电 1、适配器接口
//适配接口
public interface IVoltage5V {public int output5V();
}2、被适配的类
//被适配的类
public class Voltage220V {//输出220V的电压不变public int output220V() {int src 220;System.out.println(电压 src 伏);return src;}
}3、适配器类
//适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V {Overridepublic int output5V() {int srcV output220V();//获取220V 电压int dst srcV / 44; //转成 5vreturn dst;}}4、使用者
public class Phone {//充电public void charging(IVoltage5V iVoltage5V) {if(iVoltage5V.output5V() 5) {System.out.println(电压为5V, 可以充电~~);} else if (iVoltage5V.output5V() 5) {System.out.println(电压大于5V, 不能充电~~);}}
}5、测试 public static void main(String[] args) {Phone phone new Phone();phone.charging(new VoltageAdapter());}电压220伏 电压为5V, 可以充电~~
3总结
1Java 是单继承机制所以类适配器需要继承 src 类这一点算是一个缺点,因为这要求 dst 必须是接口有一定局限性;
2src 类的方法在 Adapter 中都会暴露出来也增加了使用的成本。
3由于其继承了 src 类所以它可以根据需求重写 src 类的方法使得 Adapter 的灵活性增强了。
3、对象适配器模式
1介绍
1基本思路和类的适配器模式相同只是将 Adapter 类作修改不是继承 src 类而是持有 src 类的实例以解决兼容性的问题。 即持有 src类实现 dst 类接口完成 src-dst 的适配
2根据“合成复用原则”在系统中尽量使用关联关系(聚合)来替代继承关系。
3对象适配器模式是适配器模式常用的一种 2案例
3、修改类适配器第三步改为对象适配
//适配器类
public class VoltageAdapter implements IVoltage5V {private Voltage220V voltage220V; // 关联关系-聚合//通过构造器传入一个 Voltage220V 实例public VoltageAdapter(Voltage220V voltage220v) {this.voltage220V voltage220v;}Overridepublic int output5V() {int dst 0;if(null ! voltage220V) {int src voltage220V.output220V();//获取220V 电压System.out.println(使用对象适配器进行适配~~);dst src / 44;System.out.println(适配完成输出的电压为 dst);}return dst;}}测试 public static void main(String[] args) {Phone phone new Phone();phone.charging(new VoltageAdapter(new Voltage220V()));}电压220伏 使用对象适配器进行适配~~ 适配完成输出的电压为5 电压为5V, 可以充电~~
3总结
1对象适配器和类适配器其实算是同一种思想只不过实现方式不同。根据合成复用原则使用组合替代继承所以它解决了类适配器必须继承 src 的局限性问题也不再要求 dst必须是接口。
2使用成本更低更灵活。
4、接口适配器模式
1介绍
1核心思路当不需要全部实现接口提供的方法时可先设计一个抽象类实现接口并为该接口中每个方法提供一个默认实现(空方法)那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。
2适用于一个接口不想使用其所有的方法的情况。
2案例 1、接口
public interface Interface4 {public void m1();public void m2();public void m3();public void m4();
}2、抽象类
//在AbsAdapter 我们将 Interface4 的方法进行默认实现
public abstract class AbsAdapter implements Interface4 {//默认实现public void m1() {}public void m2() {}public void m3() {}public void m4() {}
}3、测试 public static void main(String[] args) {AbsAdapter absAdapter new AbsAdapter() {//只需要去覆盖我们 需要使用 接口方法Overridepublic void m1() {System.out.println(使用了m1的方法);}};absAdapter.m1();}使用了m1的方法
3总结
1三种命名方式是根据 src 是以怎样的形式给到 Adapter(在 Adapter 里的形式)来命名的。
2类适配器以类给到在 Adapter 里就是将 src当做类继承
对象适配器以对象给到在 Adapter里将src 作为一个对象持有
接口适配器以接口给到在Adapter 里将src 作为一个接口实现
3Adapter 模式最大的作用还是将原本不兼容的接口融合在一起工作。
八、桥接模式
1、介绍
1桥接模式(Bridge 模式)是指将实现与抽象放在两个不同的类层次中使两个层次可以独立改变。是一种结构型设计模式。
2Bridge 模式基于类的最小设计原则通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstaction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展。
2、原理说明 说明
1Client类桥接模式的调用者
2抽象类(Abstraction)维护了 Implementor/即它的实现类 ConcretelmplementorA… 二者是聚合关系Abstraction充当桥接类
3RefinedAbstraction是 Abstraction 抽象类的子类
4Implementor行为实现类的接口
5ConcretelmplementorA/B 行为的具体实现类
6从 UM 图这里的抽象类和接口是聚合的关系其实调用和被调用关系
3、案例
手机打电话 传统类图 扩展性问题(类爆炸)如果我们再增加手机的样式(旋转式)就需要增加各个品牌手机的类同样如果我们增加一个手机品牌也要在各个手机样式类下增加。违反了单一职责原则这样增加了代码维护成本
改进类图 1、接口Brand
//接口
public interface Brand {void open();void close();void call();
}2、vivo手机
public class Vivo implements Brand {Overridepublic void open() {System.out.println( Vivo手机开机 );}Overridepublic void close() {System.out.println( Vivo手机关机 );}Overridepublic void call() {System.out.println( Vivo手机打电话 );}}3、小米手机
public class XiaoMi implements Brand {Overridepublic void open() {System.out.println( 小米手机开机 );}Overridepublic void close() {System.out.println( 小米手机关机 );}Overridepublic void call() {System.out.println( 小米手机打电话 );}}4、手机抽象类
public abstract class Phone {//组合品牌private Brand brand;//构造器public Phone(Brand brand) {super();this.brand brand;}protected void open() {brand.open();}protected void close() {brand.close();}protected void call() {brand.call();}}5、折叠手机
//折叠式手机类继承 抽象类 Phone
public class FoldedPhone extends Phone {//构造器public FoldedPhone(Brand brand) {super(brand);}public void open() {super.open();System.out.println( 折叠样式手机 );}public void close() {super.close();System.out.println( 折叠样式手机 );}public void call() {super.call();System.out.println( 折叠样式手机 );}
}6、直立手机
public class UpRightPhone extends Phone {//构造器public UpRightPhone(Brand brand) {super(brand);}public void open() {super.open();System.out.println( 直立样式手机 );}public void close() {super.close();System.out.println( 直立样式手机 );}public void call() {super.call();System.out.println( 直立样式手机 );}
}7、测试 public static void main(String[] args) {//获取折叠式手机 (样式 品牌 )Phone phone1 new FoldedPhone(new XiaoMi());phone1.open();phone1.call();phone1.close();System.out.println();Phone phone2 new FoldedPhone(new Vivo());phone2.open();phone2.call();phone2.close();}小米手机开机 折叠样式手机 小米手机打电话 折叠样式手机 小米手机关机 折叠样式手机
Vivo手机开机 折叠样式手机 Vivo手机打电话 折叠样式手机 Vivo手机关机 折叠样式手机
4、总结
1实现了抽象和实现部分的分离从而极大的提供了系统的灵活性让抽象部分和实现部分独立开来这有助于系统进行分层设计从而产生更好的结构化系统。
2对于系统的高层部分只需要知道抽象部分和实现部分的接口就可以了其它的部分由具体业务来完成。
3桥接模式替代多层继承方案可以减少子类的个数降低系统的管理和维护成本。
4桥接模式的引入增加了系统的理解和设计难度由于聚合关联关系建立在抽象层要求开发者针对抽象进行设 计和编程
5桥接模式要求正确识别出系统中两个独立变化的维度(抽象、和实现)因此其使用范围有一定的局限性。
6应用场景
JDBC 驱动程序银行转账系统 转账分类网上转账柜台转账AMT转账转账用户类型普通用户银卡用户金卡用户 消息管理 消息类型即时消息延时消息消息分类手机短信邮件消息QQ消息
九、装饰者模式
1、介绍
装饰者模式动态的将新功能附加到对象上。在对象功能扩展方面它比继承更有弹性装饰者模式也体现了开闭原则(ocp)
2、案例
1咖啡种类/单品咖啡Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
2调料Milk、Soy(豆浆)、Chocolate
3要求在扩展新的咖啡种类时具有良好的扩展性、改动方便、维护方便
4使用 OO 来计算不同种类咖啡的费用客户可以点单品咖啡也可以单品咖啡调料组合。
传统类图 1可以控制类的数量不至于造成很多的类
2在增加或者删除调料种类时代码的维护量很大
3考虑到用户可以添加多份 调料时可以将 hasMilk 返回一个对应 int
改进类图 1、drink抽象类
public abstract class Drink {public String des; // 描述private float price 0.0f;public String getDes() {return des;}public void setDes(String des) {this.des des;}public float getPrice() {return price;}public void setPrice(float price) {this.price price;}//计算费用的抽象方法//子类来实现public abstract float cost();}2、coffee类
public class Coffee extends Drink {Overridepublic float cost() {return super.getPrice();}}3、浓缩咖啡
public class ShortBlack extends Coffee{public ShortBlack() {setDes( shortblack );setPrice(4.0f);}
}4、无因咖啡
public class DeCaf extends Coffee {public DeCaf() {setDes( 无因咖啡 );setPrice(1.0f);}
}5、意大利咖啡
public class Espresso extends Coffee {public Espresso() {setDes( 意大利咖啡 );setPrice(6.0f);}
}6、美式咖啡
public class LongBlack extends Coffee {public LongBlack() {setDes( longblack );setPrice(5.0f);}
}以上都是咖啡类型
7、装饰类
public class Decorator extends Drink {private Drink obj;public Decorator(Drink obj) { //组合this.obj obj;}Overridepublic float cost() {// getPrice 自己价格return super.getPrice() obj.cost();}Overridepublic String getDes() {// obj.getDes() 输出被装饰者的信息return des getPrice() obj.getDes();}}8、巧克力
//具体的Decorator 这里就是调味品
public class Chocolate extends Decorator {public Chocolate(Drink obj) {super(obj);setDes( 巧克力 );setPrice(3.0f); // 调味品 的价格}}9、牛奶
public class Milk extends Decorator {public Milk(Drink obj) {super(obj);setDes( 牛奶 );setPrice(2.0f); }}10、豆浆
public class Soy extends Decorator{public Soy(Drink obj) {super(obj);setDes( 豆浆 );setPrice(1.5f);}}11、测试 public static void main(String[] args) {// 装饰者模式下的订单2份巧克力一份牛奶的LongBlack// 1. 点一份 LongBlackDrink order new LongBlack();System.out.println(费用1 order.cost());System.out.println(描述 order.getDes());// 2. order 加入一份牛奶order new Milk(order);System.out.println(order 加入一份牛奶 费用 order.cost());System.out.println(order 加入一份牛奶 描述 order.getDes());// 3. order 加入一份巧克力order new Chocolate(order);System.out.println(order 加入一份牛奶 加入一份巧克力 费用 order.cost());System.out.println(order 加入一份牛奶 加入一份巧克力 描述 order.getDes());// 3. order 加入一份巧克力order new Chocolate(order);System.out.println(order 加入一份牛奶 加入2份巧克力 费用 order.cost());System.out.println(order 加入一份牛奶 加入2份巧克力 描述 order.getDes());System.out.println();Drink order2 new DeCaf();System.out.println(order2 无因咖啡 费用 order2.cost());System.out.println(order2 无因咖啡 描述 order2.getDes());order2 new Milk(order2);
x System.out.println(order2 无因咖啡 加入一份牛奶 费用 order2.cost());System.out.println(order2 无因咖啡 加入一份牛奶 描述 order2.getDes());}描述 longblack order 加入一份牛奶 费用 7.0 order 加入一份牛奶 描述 牛奶 2.0 longblack order 加入一份牛奶 加入一份巧克力 费用 10.0 order 加入一份牛奶 加入一份巧克力 描述 巧克力 3.0 牛奶 2.0 longblack order 加入一份牛奶 加入2份巧克力 费用 13.0 order 加入一份牛奶 加入2份巧克力 描述 巧克力 3.0 巧克力 3.0 牛奶 2.0 longblack order2 无因咖啡 费用 1.0 order2 无因咖啡 描述 无因咖啡 order2 无因咖啡 加入一份牛奶 费用 3.0 order2 无因咖啡 加入一份牛奶 描述 牛奶 2.0 无因咖啡
3、jdk中的使用
Java 的 IO 结构FilterInputStream 就是一个装饰者 public static void main(Stringl args) throws Exception{//说明//1.nputStream 是抽象类,类似我们前面讲的 Drink//2. FilelnputStream 是InputStream 子类类似我们前面的 DeCaf, LongBlack//3.FilterlnputStream 是 InputStream 子类:类似我们前面 的 Decorator 修饰者//4. DatalnputStream 是 FilterlnputStream 子类具体的修饰者类似前面的 Mik, Soy 等//5.FilterInputStream 类有protected volatile InputStream in;即含被装饰者//6.分析得出在 jdk 的io体系中就是使用装饰者模式DatalnputStream dis new DatalnputStream(new FileInputStream(d:\\abc.txt ))System.out.println(dis.read());dis.close();
}十、组合模式
1、介绍
1组合模式(Composite Pattern)又叫部分整体模式它创建了对象组的树形结构将对象组合成树状结构以表示**“整体-部分”**的层次关系。
2组合模式依据树形结构来组合对象用来表示部分以及整体层次。
3组合模式使得用户对单个对象和组合对象的访问具有一致性即组合能让客户以一致的方式处理个别对象以 及组合对象
2、原理 1Component这是组合中对象声明接口在适当情况下实现所有类共有的接口默认行为,用于访问和管理Component 子部件,Component 可以是抽象类或者接口
2Leaf在组合中表示叶子节点叶子节点没有子节点
3Composite非叶子节点 用于存储子部件 在 Component 接口中实现 子部件的相关操作比如增加(add)删除。
3、案例
编写程序展示一个学校院系结构要在一个页面中展示出学校的院系组成,一个学校有多个学院,个学院有多个系。 1、抽象类
public abstract class OrganizationComponent {private String name; // 名字private String des; // 说明protected void add(OrganizationComponent organizationComponent) {//默认实现throw new UnsupportedOperationException();}protected void remove(OrganizationComponent organizationComponent) {//默认实现throw new UnsupportedOperationException();}//构造器public OrganizationComponent(String name, String des) {super();this.name name;this.des des;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getDes() {return des;}public void setDes(String des) {this.des des;}//方法print, 做成抽象的, 子类都需要实现protected abstract void print();}2、学校
//University 就是 Composite , 可以管理College
public class University extends OrganizationComponent {ListOrganizationComponent organizationComponents new ArrayListOrganizationComponent();// 构造器public University(String name, String des) {super(name, des);}// 重写addOverrideprotected void add(OrganizationComponent organizationComponent) {organizationComponents.add(organizationComponent);}// 重写removeOverrideprotected void remove(OrganizationComponent organizationComponent) {organizationComponents.remove(organizationComponent);}Overridepublic String getName() {return super.getName();}Overridepublic String getDes() {return super.getDes();}// print方法就是输出University 包含的学院Overrideprotected void print() {System.out.println(-------------- getName() --------------);//遍历 organizationComponents for (OrganizationComponent organizationComponent : organizationComponents) {organizationComponent.print();}}}3、学院
public class College extends OrganizationComponent {//List 中 存放的DepartmentListOrganizationComponent organizationComponents new ArrayListOrganizationComponent();// 构造器public College(String name, String des) {super(name, des);}// 重写addOverrideprotected void add(OrganizationComponent organizationComponent) {// 将来实际业务中Colleage 的 add 和 University add 不一定完全一样organizationComponents.add(organizationComponent);}// 重写removeOverrideprotected void remove(OrganizationComponent organizationComponent) {organizationComponents.remove(organizationComponent);}Overridepublic String getName() {return super.getName();}Overridepublic String getDes() {return super.getDes();}// print方法就是输出University 包含的学院Overrideprotected void print() {System.out.println(-------------- getName() --------------);//遍历 organizationComponents for (OrganizationComponent organizationComponent : organizationComponents) {organizationComponent.print();}}}4、院系
public class Department extends OrganizationComponent {//没有集合public Department(String name, String des) {super(name, des);}//add , remove 就不用写了因为他是叶子节点Overridepublic String getName() {return super.getName();}Overridepublic String getDes() {return super.getDes();}Overrideprotected void print() {System.out.println(getName());}}5、测试
public static void main(String[] args) {//从大到小创建对象 学校OrganizationComponent university new University(清华大学, 中国顶级大学 );//创建 学院OrganizationComponent computerCollege new College(计算机学院, 计算机学院 );OrganizationComponent infoEngineercollege new College(信息工程学院, 信息工程学院 );//创建各个学院下面的系(专业)computerCollege.add(new Department(软件工程, 软件工程不错 ));computerCollege.add(new Department(网络工程, 网络工程不错 ));computerCollege.add(new Department(计算机科学与技术, 计算机科学与技术是老牌的专业 ));infoEngineercollege.add(new Department(通信工程, 通信工程不好学 ));infoEngineercollege.add(new Department(信息工程, 信息工程好学 ));//将学院加入到 学校university.add(computerCollege);university.add(infoEngineercollege);university.print();
// infoEngineercollege.print();}--------------清华大学-------------- --------------计算机学院-------------- 软件工程 网络工程 计算机科学与技术 --------------信息工程学院-------------- 通信工程 信息工程
4、总结
1简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题。
2具有较强的扩展性。当要更改组合对象时我们只需要调整内部的层次关系客户端不用做出任何改动.
3方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节容易添加节点或者叶子从而创建出复杂的树形结构
4需要遍历组织机构或者处理的对象具有树形结构时非常适合使用组合模式
5要求较高的抽象性如果节点和叶子有很多差异性的话比如很多方法和属性都不一样不适合使用组合模式
十一、外观模式
1、介绍
1外观模式(Facade)也叫“过程模式外观模式为子系统中的一组接口提供一个一致的界面此模式定义了一个高层接口这个接口使得这一子系统更加容易使用
2外观模式通过定义一个一致的接口用以屏蔽内部子系统的细节使得调用端只需跟这个接口发生调用而无需关心这个子系统的内部细节
2、案例
组建一个家庭影院: DVD 播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的功能其过程为:直接用遥控器统筹各设备开关 开爆米花机 放下屏幕 开投影仪 开音响 开 DVD选 dvd 去拿爆米花 调暗灯光 播放 观影结束后关闭各种设备 1、爆米花类
public class Popcorn {private static Popcorn instance new Popcorn();public static Popcorn getInstance() {return instance;}public void on() {System.out.println( popcorn on );}public void off() {System.out.println( popcorn ff );}public void pop() {System.out.println( popcorn is poping );}
}2、屏幕类
public class Screen {private static Screen instance new Screen();public static Screen getInstance() {return instance;}public void up() {System.out.println( Screen up );}public void down() {System.out.println( Screen down );}}3、投影仪类
public class Projector {private static Projector instance new Projector();public static Projector getInstance() {return instance;}public void on() {System.out.println( Projector on );}public void off() {System.out.println( Projector ff );}public void focus() {System.out.println( Projector is Projector );}}4、音响类
public class Stereo {private static Stereo instance new Stereo();public static Stereo getInstance() {return instance;}public void on() {System.out.println( Stereo on );}public void off() {System.out.println( Screen off );}public void up() {System.out.println( Screen up.. );}}5、dvd类
public class DVDPlayer {//使用单例模式, 使用饿汉式private static DVDPlayer instance new DVDPlayer();public static DVDPlayer getInstanc() {return instance;}public void on() {System.out.println( dvd on );}public void off() {System.out.println( dvd off );}public void play() {System.out.println( dvd is playing );}public void pause() {System.out.println( dvd pause ..);}
}6、灯光类
public class TheaterLight {private static TheaterLight instance new TheaterLight();public static TheaterLight getInstance() {return instance;}public void on() {System.out.println( TheaterLight on );}public void off() {System.out.println( TheaterLight off );}public void dim() {System.out.println( TheaterLight dim.. );}public void bright() {System.out.println( TheaterLight bright.. );}
}7、统筹类家庭影院
public class HomeTheaterFacade {//定义各个子系统对象private TheaterLight theaterLight;private Popcorn popcorn;private Stereo stereo;private Projector projector;private Screen screen;private DVDPlayer dVDPlayer;//构造器public HomeTheaterFacade() {super();this.theaterLight TheaterLight.getInstance();this.popcorn Popcorn.getInstance();this.stereo Stereo.getInstance();this.projector Projector.getInstance();this.screen Screen.getInstance();this.dVDPlayer DVDPlayer.getInstanc();}//操作分成 4 步public void ready() {popcorn.on();popcorn.pop();screen.down();projector.on();stereo.on();dVDPlayer.on();theaterLight.dim();}public void play() {dVDPlayer.play();}public void pause() {dVDPlayer.pause();}public void end() {popcorn.off();theaterLight.bright();screen.up();projector.off();stereo.off();dVDPlayer.off();}}8、测试 public static void main(String[] args) {//这里直接调用。。 很麻烦HomeTheaterFacade homeTheaterFacade new HomeTheaterFacade();// 开始System.out.println(开始播放);homeTheaterFacade.ready();// 暂停System.out.println(暂停);homeTheaterFacade.play();// 结束System.out.println(结束);homeTheaterFacade.end();
开始播放 popcorn on popcorn is poping Screen down Projector on Stereo on dvd on TheaterLight dim… 暂停 dvd is playing 结束 popcorn ff TheaterLight bright… Screen up Projector ff Screen off dvd off
3、总结
1外观模式对外屏蔽了子系统的细节因此外观模式降低了客户端对子系统使用的复杂性
2外观模式对客户端与子系统的耦合关系-解耦让子系统内部的模块更易维护和扩展
3通过合理的使用外观模式可以帮我们更好的划分访问的层次
4当系统需要进行分层设计时可以考虑使用Facade 模式
5在维护一个遗留的大型系统时可能这个系统已经变得非常难以维护和扩展此时可以考虑为新系统开发一个Facade 类来提供遗留系统的比较清晰简单的接口让新系统与 Facade 类交互提高复用性
十二、享元模式
1、介绍
1享元模式(Flyweight Pattern) 也叫 蝇量模式运用共享技术有效地支持大量细粒度的对象
2常用于系统底层开发解决系统的性能问题。像数据库连接池里面都是创建好的连接对象在这些连接对象中有我们需要的则直接拿来用避免重新创建如果没有我们需要的则创建一个
3享元模式能够解决重复对象的内存浪费的问题当系统中有大量相似对象需要缓冲池时。不需总是创建新对象可以从缓冲池里拿。这样可以降低系统内存同时提高效率
4享元模式经典的应用场景就是池技术了String 常量池、数据库连接池、缓冲池等等都是享元模式的应用享 元模式是池技术的重要实现方式
2、内部状态与外部状态
1享元模式提出了两个要求细粒度和共享对象。即将对象的信息分为两个部分内部状态和外部状态 2内部状态指对象共享出来的信息存储在享元对象内部且不会随环境的改变而改变
3外部状态指对象得以依赖的一个标记是随环境改变而改变的、不可共享的状态。
3、案例
小型的外包项目给客户 A做一个产品展示网站客户A的朋友感觉效果不错也希望做这样的产品展示网站但是要求都有些不同: 1)有客户要求以新闻的形式发布 2)有客户人要求以博客的形式发布 3)有客户希望以微信公众号的形式发布 1、外部状态user
public class User {private String name;public User(String name) {super();this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;}}2、抽象类
public abstract class WebSite {public abstract void use(User user);//抽象方法
}3、具体网站
//具体网站
public class ConcreteWebSite extends WebSite {//共享的部分内部状态private String type ; //网站发布的形式(类型)//构造器public ConcreteWebSite(String type) {this.type type;}Overridepublic void use(User user) {System.out.println(网站的发布形式为: type 在使用中 .. 使用者是 user.getName());}}4、工厂类
// 网站工厂类根据需要返回压一个网站
public class WebSiteFactory {//集合 充当池的作用private HashMapString, ConcreteWebSite pool new HashMap();//根据网站的类型返回一个网站, 如果没有就创建一个网站并放入到池中,并返回public WebSite getWebSiteCategory(String type) {if(!pool.containsKey(type)) {//就创建一个网站并放入到池中pool.put(type, new ConcreteWebSite(type));}return (WebSite)pool.get(type);}//获取网站分类的总数 (池中有多少个网站类型)public int getWebSiteCount() {return pool.size();}
}5、测试
public static void main(String[] args) {// 创建一个工厂类WebSiteFactory factory new WebSiteFactory();// 客户要一个以新闻形式发布的网站WebSite webSite1 factory.getWebSiteCategory(新闻);webSite1.use(new User(tom));// 客户要一个以博客形式发布的网站WebSite webSite2 factory.getWebSiteCategory(博客);webSite2.use(new User(jack));// 客户要一个以博客形式发布的网站WebSite webSite3 factory.getWebSiteCategory(博客);webSite3.use(new User(smith));// 客户要一个以博客形式发布的网站WebSite webSite4 factory.getWebSiteCategory(博客);webSite4.use(new User(king));System.out.println(网站的分类共 factory.getWebSiteCount());}网站的发布形式为:新闻 在使用中 … 使用者是tom 网站的发布形式为:博客 在使用中 … 使用者是jack 网站的发布形式为:博客 在使用中 … 使用者是smith 网站的发布形式为:博客 在使用中 … 使用者是king 网站的分类共2
4、总结
1享元模式理解“享”就表示共享“元”表示对象
2系统中有大量对象这些对象消耗大量内存并且对象的状态大部分可以外部化时我们就可以考虑选用享元模式
3用唯一标识码判断如果在内存中有则返回这个唯一标识码所标识的对象用 HashMap/HashTable
4存储享元模式大大减少了对象的创建降低了程序内存的占用提高效率
5享元模式提高了系统的复杂度。需要分离出内部状态和外部状态而外部状态具有固化特性不应该随着内部状态的改变而改变这是我们使用享元模式需要注意的地方
6使用享元模式时注意划分内部状态和外部状态并且需要有一个工厂类加以控制。
7享元模式经典的应用场景是需要缓冲池的场景比如String 常量池、数据库连接池
十三、代理模式
1、介绍
1代理模式为一个对象提供一个替身以控制对这个对象的访问。即通过代理对象访问目标对象优点是可以在目标对象实现的基础上增强额外的功能操作即扩展目标对象的功能。
2被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
3代理模式有不同的形式。主要有三种 静态代理、动态代理(JDK 代理、接口代理)和 Cglib 代理(可以在内存动态的创建对象而不需要实现接口属于动态代理的范畴)。
2、静态代理
1介绍
静态代理在使用时需要定义接口或者父类被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类。
2案例
1定义一个接口ITeacherDao
2目标对象 TeacherDA0 实现接口 ITeacherDAO
3使用静态代理方式就需要在代理对象 TeacherDAOProxy 中也实现 ITeacherDAO
4调用的时候通过调用代理对象的方法来调用目标对象
5代理对象与目标对象要实现相同的接口然后通过调用相同的方法来调用目标对象的方法 1、接口
//接口
public interface ITeacherDao {void teach(); // 授课的方法
}2、目标对象
public class TeacherDao implements ITeacherDao {Overridepublic void teach() {System.out.println( 老师授课中 。。。。。);}}3、代理对象
//代理对象,静态代理
public class TeacherDaoProxy implements ITeacherDao{private ITeacherDao target; // 目标对象通过接口来聚合//构造器public TeacherDaoProxy(ITeacherDao target) {this.target target;}Overridepublic void teach() {System.out.println(开始代理 完成某些操作。。。。。 );//方法target.teach();System.out.println(提交。。。。。);//方法}}4、测试 public static void main(String[] args) {// TODO Auto-generated method stub//创建目标对象(被代理对象)TeacherDao teacherDao new TeacherDao();//创建代理对象, 同时将被代理对象传递给代理对象TeacherDaoProxy teacherDaoProxy new TeacherDaoProxy(teacherDao);//通过代理对象调用到被代理对象的方法//即执行的是代理对象的方法代理对象再去调用目标对象的方法 teacherDaoProxy.teach();}开始代理 完成某些操作。。。。。 老师授课中 。。。。。 提交。。。。。
3总结
1优点在不修改目标对象的功能前提下能通过代理对象对目标功能扩展
2缺点因为代理对象需要与目标对象实现一样的接口所以会有很多代理类
3一旦接口增加方法目标对象与代理对象都要维护
3、动态代理
1介绍
1代理对象,不需要实现接口但是目标对象要实现接口否则不能用动态代理
2代理对象的生成是利用JDK的API动态的在内存中构建代理对象
3动态代理也叫做JDK 代理、接口代理
4在jdk中生成代理对象api 代理类所在包java.lang.reflect.Proxy JDK 实现代理只需要使用 newProxyInstance 方法但是该方法需要接收三个参数写法是: static Obiect newProxyInstance(ClassLoader loader. Class? interfaces.InvocationHandler h)
2案例
将静态代理改为动态代理 1、接口
//接口
public interface ITeacherDao {void teach(); // 授课方法void sayHello(String name);
}2、目标对象实现
public class TeacherDao implements ITeacherDao {Overridepublic void teach() {System.out.println( 老师授课中.... );}Overridepublic void sayHello(String name) {System.out.println(hello name);}}3、代理
public class ProxyFactory {//维护一个目标对象 , Objectprivate Object target;//构造器 对target 进行初始化public ProxyFactory(Object target) {this.target target;} //给目标对象 生成一个代理对象public Object getProxyInstance() {//说明/** public static Object newProxyInstance(ClassLoader loader,Class?[] interfaces,InvocationHandler h)//1. ClassLoader loader 指定当前目标对象使用的类加载器, 获取加载器的方法固定//2. Class?[] interfaces: 目标对象实现的接口类型使用泛型方法确认类型//3. InvocationHandler h : 事情处理执行目标对象的方法时会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入*/return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(JDK代理开始~~);//反射机制调用目标对象的方法Object returnVal method.invoke(target, args);System.out.println(JDK代理提交);return returnVal;}}); }}4、测试 public static void main(String[] args) {//创建目标对象ITeacherDao target new TeacherDao();//给目标对象创建代理对象, 可以转成 ITeacherDaoITeacherDao proxyInstance (ITeacherDao)new ProxyFactory(target).getProxyInstance();// proxyInstanceclass com.sun.proxy.$Proxy0 内存中动态生成了代理对象System.out.println(proxyInstance proxyInstance.getClass());//通过代理对象调用目标对象的方法//proxyInstance.teach();proxyInstance.sayHello( tom );}proxyInstanceclass com.sun.proxy.$Proxy0 JDK代理开始~~ hello tom JDK代理提交
4、Cglib代理
1介绍
1静态代理和JDK 代理模式都要求目标对象是实现一个接口但是有时候目标对象只是一个单独的对象并没有实现任何的接口这个时候可使用目标对象子类来实现代理-这就是 Cglib 代理
2Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展有些书也将Cglib代理归属到动态代理。
3Cglib 是一个强大的高性能的代码生成包它可以在运行期扩展java类与实现 java接口它广泛的被许多 AOP 的框架使用例如 Spring AOP实现方法拦截
4在 AOP 编程中如何选择代理模式 目标对象需要实现接口用 JDK 代理 目标对象不需要实现接口用 Cglib 代理
5Cglib 包的底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类
2实现步骤
1引入cglib的jar包 2在内存中动态构建子类注意代理的类不能为fnal否则报错 java.lang.IllegalArgumentException:
3目标对象的方法如果为 final/static那么就不会被拦截即不会执行目标对象额外的业务方法
3案例 1、目标对象
public class TeacherDao {public String teach() {System.out.println( 老师授课中 我是cglib代理不需要实现接口 );return hello;}
}2、代理类
public class ProxyFactory implements MethodInterceptor {//维护一个目标对象private Object target;//构造器传入一个被代理的对象public ProxyFactory(Object target) {this.target target;}//返回一个代理对象: 是 target 对象的代理对象public Object getProxyInstance() {//1. 创建一个工具类Enhancer enhancer new Enhancer();//2. 设置父类enhancer.setSuperclass(target.getClass());//3. 设置回调函数enhancer.setCallback(this);//4. 创建子类对象即代理对象return enhancer.create();}//重写 intercept 方法会调用目标对象的方法Overridepublic Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {System.out.println(Cglib代理模式 ~~ 开始);Object returnVal method.invoke(target, args);System.out.println(Cglib代理模式 ~~ 提交);return returnVal;}}3、测试
public static void main(String[] args) {//创建目标对象TeacherDao target new TeacherDao();//获取到代理对象并且将目标对象传递给代理对象TeacherDao proxyInstance (TeacherDao)new ProxyFactory(target).getProxyInstance();//执行代理对象的方法触发intecept 方法从而实现 对目标对象的调用String res proxyInstance.teach();System.out.println(res res);
}Cglib代理模式 ~~ 开始 老师授课中 我是cglib代理不需要实现接口 Cglib代理模式 ~~ 提交 reshello