概述:
java 语言面向对象的三大特征:封装、继承、多态。
- 封装性
- 封装性就是把对象的属性和服务结合成一个独立的相同单位,并尽可能隐蔽对象的内部细节,包含两个含义:
- 把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位(即对象)。
- 信息隐蔽,即尽可能隐蔽对象的内部细节,对外形成一个边界〔或者说形成一道屏障〕,只保留有限的对外接口使之与外部发生联系。
- 封装的原则在软件上的反映是:要求使对象以外的部分不能随意存取对象的内部数据(属性),从而有效的避免了外部错误对它的”交叉感染”,使软件错误能够局部化,大大减少查错和排错的难度。
- 封装性就是把对象的属性和服务结合成一个独立的相同单位,并尽可能隐蔽对象的内部细节,包含两个含义:
继承性
- 特殊类的对象拥有其一般类的全部属性与服务,称作特殊类对一般类的继承。一个类可以是多个一般类的特殊类,它从多个一般类中继承了属性与服务,这称为多继承。在java语言中,通常我们称一般类为父类(superclass,超类),特殊类为子类(subclass)。
多态性
- 对象的多态性是指在一般类中定义的属性或服务被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或服务在一般类及其各个特殊 类中具有不同的语义。例如:”几何图形”的”绘图”方法,”椭圆”和”多边形”都是”几何图”的子类,其”绘图”方法功能不同。
- 封装性
- java 语言面向对象的六大原则
- 开闭原则
- 单一职责原则
- 里氏替换原则
- 依赖倒置原则
- 接口隔离原则
- 迪米特原则
1.单例设计模式
- 保证类在内存中只有一个对象。
- 如何保证类在内存中只有一个对象呢?
- 控制类的创建,不让其他类来创建本类的对象,也就是私有化构造;
- 在本类中定义本类的对象;
- 提供公共的访问方式;
单例的几种写法
饿汉式:直接new出对象,这种就是以空间换时间
//饿汉式 class Singleton { //1,私有构造函数 private Singleton(){} //2,创建本类对象 private static Singleton s = new Singleton(); //3,对外提供公共的访问方法 public static Singleton getInstance() { return s; } public static void print() { System.out.println("饿汉式的方法"); } }
(2)懒汉式 面试写这种方式。多线程的问题?
//懒汉式,单例的延迟加载模式 class Singleton { //1,私有构造函数 private Singleton(){} //2,声明一个本类的引用 private static Singleton s; //3,对外提供公共的访问方法 public static Singleton getInstance() { if(s == null) //线程1,线程2(可能某个对象在wait()) s = new Singleton(); return s; } public static void print() { System.out.println("懒汉式的方法"); } } * 饿汉式和懒汉式的区别 * 1,饿汉式是空间换时间,懒汉式是时间换空间 * 2,在多线程访问时,饿汉式不会创建多个对象,而懒汉式有可能会创建多个对象 */ 由于懒汉式存在线程安全的问题,所以我们可以这样做: 使用双重检测锁机制,先检测是否为空,如果为空再对该单例类加锁,再判断一次是否为空,这样既解决了线程的安全问题,也避免了每次使用单例都要加锁带来的系统资源的消耗。代码如下: class Singleton { //1,私有构造函数 private Singleton(){} //2,声明一个本类的引用 private static volatile Singleton s; //3,对外提供公共的访问方法 public static Singleton getInstance() { if(s == null) Synchronized(Singleton.class){ if(s == null) { s = new Singleton(); } } return s; } public static void print() { System.out.println("懒汉式的方法"); } }
(3)第三种格式
class Singleton { private Singleton() {} public static final Singleton s = new Singleton();//final是最终的意思,被final修饰的变量不可以被更改 }
2.装饰设计模式
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。
public class Demo_Wrap {
/**
* @param args
* 装饰设计模式的好处是:
* 耦合性不强,被装饰的类的变化与装饰类的变化无关
*/
public static void main(String[] args) {
AdvanceStudent as = new AdvanceStudent(new Student());
as.code();
}
}
interface Coder {
public void code();
}
class Student implements Coder {
@Override
public void code() {
System.out.println("javase");
System.out.println("javaweb");
}
}
class AdvanceStudent implements Coder {
//1,获取被装饰类的引用
private Student s; //获取学生引用
//2,在构造方法中传入被装饰类的对象
public AdvanceStudent(Student s) {
this.s = s;
}
//3,对原有的功能进行升级
@Override
public void code() {
s.code();
System.out.println("ssh");
System.out.println("数据库");
System.out.println("大数据");
System.out.println("...");
}
}
3.简单工厂设计模式
- 简单工厂模式概述
- 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
- 优点
- 客户端不需要在负责对象的创建,从而明确了各个类的职责
- 缺点
- 这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护
- 案例演示
- 动物抽象类:public abstract Animal { public abstract void eat(); }
- 具体狗类:public class Dog extends Animal {}
- 具体猫类:public class Cat extends Animal {}
- 开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。
//动物抽象类 public abstract class Animal { public abstract void eat(); } //猫类 public class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } } //狗类 public class Dog extends Animal { @Override public void eat() { System.out.println("狗吃肉"); } } //动物工厂类 public class AnimalFactory { /*public static Dog createDog() { return new Dog(); } public static Cat createCat() { return new Cat(); }*/ //发现方法会定义很多,复用性太差 //改进 public static Animal createAnimal(String name) { if("dog".equals(name)) { return new Dog(); }else if("cat".equals(name)) { return new Cat(); }else { return null; } } } //测试类 public class Test { /** * @param args */ public static void main(String[] args) { //Dog d = AnimalFactory.createDog(); Dog d = (Dog) AnimalFactory.createAnimal("dog"); d.eat(); Cat c = (Cat) AnimalFactory.createAnimal("cat"); c.eat(); } }
4.工厂方法设计模式
- 工厂方法模式概述
- 工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
- 优点
- 客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
- 缺点
- 需要额外的编写代码,增加了工作量
案例演示
- 动物抽象类:public abstract Animal { public abstract void eat(); }
- 工厂接口:public interface Factory {public abstract Animal createAnimal();}
- 具体狗类:public class Dog extends Animal {}
- 具体猫类:public class Cat extends Animal {}
开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。发现每次修改代码太麻烦,用工厂方法改进,针对每一个具体的实现提供一个具体工厂。 - 狗工厂:public class DogFactory implements Factory {
public Animal createAnimal() {…}
} 猫工厂:public class CatFactory implements Factory {
public Animal createAnimal() {…}
}//动物抽象类 public abstract class Animal { public abstract void eat(); } //工厂接口 public interface Factory { public Animal createAnimal(); } //猫工厂类 public class CatFactory implements Factory { @Override public Animal createAnimal() { return new Cat(); } } //猫类 public class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } } //狗工厂类 public class DogFactory implements Factory { @Override public Animal createAnimal() { return new Dog(); } } //狗类 public class Dog extends Animal { @Override public void eat() { System.out.println("狗吃肉"); } } //测试类 public class Test { /** * @param args */ public static void main(String[] args) { DogFactory df = new DogFactory(); Dog d = (Dog) df.createAnimal(); d.eat(); } }
5.抽象工厂设计模式
- 定义:提供一个创建一系列相关或者相互依赖产品的接口, 而无需制定他们的具体类,一对多的关系。抽象工厂模式是 工厂方法模式的升级版。
- 例子: 我们接着前边土豪的故事继续讲。话说这个土豪还有一个爱好,就是打猎。但是土豪打猎是有要求的(毕竟土豪嘛,要就就得高一点),他如果坐Audi车去打猎,那么他就一定要使用AK47这把枪(这是去打猎吗?);如果他坐Benz车去打猎那么他就一定要用M4A1这把枪,如果按照我们前边讲的工厂方法模式来编程,那么应该是建立一个Car的抽象工厂类CarFactory,然后Benz车的工厂继承自这个抽象的父类并实现生产Benz车的方法,Audi车的工厂继承自这个抽象的父类并实现生产Audi车的方法。并且还要有一个生产Gun的抽象工厂类,由它的具体子类工厂来实现生产AK47和M4A1。这样做是非常麻烦的,我们已经知道了如果土豪做Audi的话那他一定是使用AK47,所以我们可以使用一个工厂来同时生产Audi车和AK47,注意我说的前提是我们已经知道了土豪一定是Audi车和AK47一起使用的,如果不满足这个条件的话是不能使用抽象工厂模式来解决这个问题的。
优点:即符合面向对象设计的“开闭原则”和“单一职责原 则”。又减少了系统中的类的数量,不用像工厂方法一样每生 产一个产品都要有一个具体的工厂类。
/** * 仅仅定义生产同一族产品的两个不同等级结构的产品接口,具体的实现由子类工厂来实现 * @Mr.Wu * */ public abstract class AbstractFactory { public abstract Car getCar(); public abstract Gun getGun(); } /** * Audi车的工厂同时生产Audi车和配套的AK47 * @Mr.Wu * */ public class AudiFactory extends AbstractFactory{ public Car getCar() { return new Audi(); } public Gun getGun() { return new AK47(); } } /** * Benz车的工厂同时生产Benz车和配套的M4A1 * @Mr.Wu * */ public class BenzFactory extends AbstractFactory{ public Car getCar() { return new Benz(); } public Gun getGun() { return new M4A1(); } } //gun的抽象类 public abstract class Gun { abstract void fire(); } //M4A1的具体类 public class M4A1 extends Gun{ public M4A1(){ System.out.println("Create an M4A1"); } public void fire(){ System.out.println("M4A1 start fire"); } } //AK47的类 public class AK47 extends Gun{ public AK47(){ System.out.println("Create an AK47"); } public void fire(){ System.out.println("AK47 start fire"); } } //车的抽象类 public abstract class Car { abstract void drive(); } //奥迪车的类 public class Audi extends Car{ public Audi(){ System.out.println("Create a Audi"); } public void drive(){ System.out.println("Audi start engine"); } } //奔驰车的类 public class Benz extends Car{ public Benz(){ System.out.println("Create a Benz"); } public void drive(){ System.out.println("Benz start engine"); } } //测试类 public class Main { public static void main(String[] args) throws Exception { //奔驰车司机 AbstractFactory factory = new BenzFactory(); //今天想做奥迪车 Car car = factory.getCar(); //开车 car.drive(); //获得开Benz时要用的枪 Gun gun = factory.getGun(); //开火 gun.fire(); } }
说明:当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。
6.适配器设计模式
public class Demo_Adapter {
/**
* @param args
* 适配器设计模式
* 鲁智深
*/
public static void main(String[] args) {
鲁智深 鲁智深 = new 鲁智深();
鲁智深.习武();
}
}
interface 和尚 {
public void 打坐();
public void 念经();
public void 撞钟();
public void 习武();
}
abstract class 天罡星 implements 和尚 { //声明成抽象的原因是,不想让其他类创建本类对象,因为创建也没有意义,方法都是空的
@Override
public void 打坐() {
}
@Override
public void 念经() {
}
@Override
public void 撞钟() {
}
@Override
public void 习武() {
}
}
class 鲁智深 extends 天罡星 {
public void 习武() {
System.out.println("倒拔垂杨柳");
System.out.println("拳打镇关西");
System.out.println("大闹野猪林");
System.out.println("......");
}
}
7.模板方法设计模式
- 模版设计模式概述
模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。 优点和缺点
- 优点:使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求
缺点:如果算法骨架有修改的话,则需要修改抽象类
public class Demo1_Template { /** * @param args */ public static void main(String[] args) { /*long start = System.currentTimeMillis(); for(int i = 0; i < 1000000; i++) { System.out.println("x"); } long end = System.currentTimeMillis(); System.out.println(end - start);*/ Demo d = new Demo(); System.out.println(d.getTime()); } } abstract class GetTime { public final long getTime() { long start = System.currentTimeMillis(); code(); long end = System.currentTimeMillis(); return end - start; } //final修饰,目的是不让被重写 public abstract void code(); //由子类取实现想测试的代码 } class Demo extends GetTime { @Override public void code() { int i = 0; while(i < 100000) { System.out.println("x"); i++; } } }
7.观察者设计模式
- 定义:又名发布—订阅模式,对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
组成部分:
抽象目标(被观察者)角色(Subject):目标角色知道它的观察者,可以 有任意多个观察者观察同一个目标。并且提供注册和删除观 察者对象、通知观察者的方法。目标角色往往由抽象类或者 接口来实现。
抽象观察者角色(Observer):为那些在目标发生改变时需
要获得通知的对象定义一个更新接口,里面有一个更新数据 的方法。抽象观察者角色主要由抽象类或者接口来实现。- 具体目标(被观察者)角色(Concrete Subject):实现Subject,实现添 加、删除观察者、通知观察者的方法,当它的状态发生改变 时, 向它的各个观察者发出通知。
- 具体观察者角色(Concrete Observer):实现Observer的更 新接口以使自身状态与目标的状态保持一致,获取通知进行 更新。
观察者模式中,一个被观察者管理所有相依于它的观察者物件,并且在本身的状态改变时主动发出通知。这通常通过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
举例:珠宝商运送一批钻石,有黄金强盗准备抢劫,珠宝商雇佣了私人保镖,警察局也派人护送,于是当运输车上路的时候,强盗保镖警察都要观察运输车一举一动,
抽象的观察者 public interface Watcher { public void update(); } 抽象的被观察者,在其中声明方法(添加、移除观察者,通知观察者): public interface Watched { public void addWatcher(Watcher watcher); public void removeWatcher(Watcher watcher); public void notifyWatchers(); } 具体的观察者 保镖 public class Security implements Watcher { @Override public void update() { System.out.println(“运输车有行动,保安贴身保护"); } } 强盗 public class Thief implements Watcher { @Override public void update() { System.out.println(“运输车有行动,强盗准备动手"); } } 警察 public class Police implements Watcher { @Override public void update() { System.out.println(“运输车有行动,警察护航"); } } 具体的被观察者 public class Transporter implements Watched { private List<Watcher> list = new ArrayList<Watcher>(); @Override public void addWatcher(Watcher watcher) { list.add(watcher); } @Override public void removeWatcher(Watcher watcher) { list.remove(watcher); } @Override public void notifyWatchers(String str) { for (Watcher watcher : list) { watcher.update(); } } } 测试类 public class Test { public static void main(String[] args) { Transporter transporter = new Transporter(); Police police = new Police(); Security security = new Security(); Thief thief = new Thief(); transporter.addWatcher(police); transporter.addWatcher(security); transporter.addWatcher(security); transporter.notifyWatchers(); } }
我推你拉例子中没有关于数据和状态的变化通知,只是简单通知到各个观察者,告诉他们被观察者有行动。
观察者模式在关于目标角色、观察者角色通信的具体实现中,有两个版本。- 一种情况便是目标角色在发生变化后,仅仅告诉观察者角色“我变化了”,观察者角色如果想要知道具体的变化细节,则就要自己从目标角色的接口中得到。这种模式被很形象的称为:拉模式——就是说变化的信息是观察者角色主动从目标角色中“拉”出来的。
- 还有一种方法,那就是我目标角色“服务一条龙”,通知你发生变化的同时,通过一个参数将变化的细节传递到观察者角色中去。这就是“推模式”——管你要不要,先给你啦。
- 这两种模式的使用,取决于系统设计时的需要。如果目标角色比较复杂,并且观察者角色进行更新时必须得到一些具体变化的信息,则“推模式”比较合适。如果目标角色比较简单,则“拉模式”就很合适啦。
8.代理设计模式
- 什么是代理模式:代理模式的作用是,为其他对象提供一种代理以控制对这个对象的访问。
- 好处:在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
- 代理模式一般涉及到的角色有:
- 抽象角色:声明真实对象和代理对象的共同接口;
- 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
- 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
应用场景举例:比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时是这样的体现的先说说这个场景中的要素:一种类型的女人,潘金莲,王婆,西门庆,后来扩展的贾氏也和西门庆勾上了,我们是假设的,然后西门庆找潘金莲happy,但潘金莲不好意思直接,就找个王婆代理呗。我们看看具体代码。
先定义一种女人 /** * * @author Mr.Wu *定义一种类型的女人,王婆和潘金莲都属于这个类型的女人 */ public interface KindWoman { //这种女人能做什么事情呢? public void makeEyesWithMan();//抛媚眼 public void happyWithMan();//和男人那个.... } 一种类型嘛,那肯定是接口,定义个潘金莲 /** * * @author Mr.Wu *定义一个潘金莲是什么样的人 */ public class PanJinLian implements KindWoman{ @Override public void happyWithMan() { System.out.println("潘金莲和男人在做那个..."); } @Override public void makeEyesWithMan() { System.out.println("潘金莲抛媚眼..."); } } 再定义个丑陋的王婆 /** * * @author Mr.Wu *王婆这个人老聪明了,她太老了,是个男人都看不上她, *但是她有智慧经验呀,他作为一类女人的代理! */ public class WangPo implements KindWoman { private KindWoman kindWoman; public WangPo(){ //默认的话是潘金莲的代理 this.kindWoman = new PanJinLian(); } //她可以是KindWomam的任何一个女人的代理,只要你是这一类型 public WangPo(KindWoman kindWoman){ this.kindWoman = kindWoman; } @Override public void happyWithMan() { //自己老了,干不了了,但可以叫年轻的代替。 this.kindWoman.happyWithMan(); } @Override public void makeEyesWithMan() { //王婆年纪大了,谁看她抛媚眼啊 this.kindWoman.makeEyesWithMan(); } } 两个女主角都上场了,该男主角了,定义个西门庆 /** * * @author Mr.Wu *水浒传是这样写的:西门庆被潘金莲用竹竿敲了一下,西门庆看痴迷了,被王婆看到了,就开始撮合两人好事,王婆作为潘金莲的代理人收了不少好处费,那我们假设一下: *如果没有王婆在中间牵线,这两个不要脸的能成事吗?难说得很! */ public class XiMenQing { /** * @param args */ public static void main(String[] args) { WangPo wangPo; //把王婆叫出来 wangPo = new WangPo(); //然后西门庆说,我要和潘金莲Happy,然后王婆就安排了西门庆丢筷子哪出戏: wangPo.makeEyesWithMan(); //看到没有表面是王婆在做,其实爽的是潘金莲 wangPo.happyWithMan(); } } 那这就是活生生的一个例子,通过代理人实现了某种目的,如果真去了王婆这个中间环节,直接西门庆和潘金莲勾搭,估计很难成就武松杀嫂事件。 那我们再考虑一下,水浒里面还有没有这类型的女人?有,卢俊义的老婆贾氏(就是和那个管家苟合的那个),这个名字起的:“贾氏”,那我们也让王婆做她的代理: /** * * @author Mr.Wu *定义一个贾氏是什么样的人 */ public class JiaShi implements KindWoman { @Override public void happyWithMan() { System.out.println("贾氏和男人在做那个..."); } @Override public void makeEyesWithMan() { System.out.println("贾氏抛媚眼..."); } } 西门庆勾潘金莲又勾引贾氏 /** * * @author Mr.Wu *水浒传是这样写的:西门庆被潘金莲用竹竿敲了一下,西门庆看痴迷了,被王婆看到了,就开始撮合两人好事,王婆作为潘金莲的代理人收了不少好处费,那我们假设一下: *如果没有王婆在中间牵线,这两个不要脸的能成事吗?难说得很! */ public class XiMenQing { /** * @param args */ public static void main(String[] args) { WangPo wangPo; //把王婆叫出来 wangPo = new WangPo(); //然后西门庆说,我要和潘金莲Happy,然后王婆就安排了西门庆丢筷子哪出戏: wangPo.makeEyesWithMan(); //看到没有表面是王婆在做,其实爽的是潘金莲 wangPo.happyWithMan(); //西门庆勾引贾氏 JiaShi jiaShi = new JiaShi(); wangPo = new WangPo(jiaShi); wangPo.makeEyesWithMan(); wangPo.happyWithMan(); } }
说完这个故事,那我总结一下,代理模式主要使用了java的多态,干活的是被代理类,代理类主要是接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,大家知根知底,你能做啥,我能做啥都清楚得很,同样一个接口呗。好了不多说了,慢慢体会吧。
9.策略设计模式
…待续
10.建造者设计模式
…待续