六、设计模式
1. 单例模式
核心作用:保证一个类只有一个对象,提供一个方法访问这个对象。例如:回收站和任务管理器Spring的Bean就是。
优点:减少系统性能的开销。
实现方式:饿汉式,懒汉式 其他:双重检测锁,静态内部类,枚举单例
- 饿汉式
私有构造器,提供一个私有属性(创建一个对象),提供一个取对象方法。
public class Demo1 {
//饿汉式,类初始化时立刻加载,线程安全调用效率高
private static Demo1 demo1 = new Demo1();
private Demo1(){
}
public static Demo1 getDemo1(){
return demo1;
}
}
- 懒汉式
public class Demo1 {
//懒汉式,需要加载同步块,资源利用率高,调用效率低
private static Demo1 demo1;
private Demo1(){
}
public static synchronized Demo1 getDemo1(){
if (demo1 == null)
demo1 = new Demo1();
return demo1;
}
}
2. 工厂模式
核心本质是实例化对象,用工厂方法代替new操作。将选择实现类,创建对象统一管理和控制,从而将调用者和实现类解耦。
- OCP(开闭原则):一个软件的实体应该对扩展开放,对修改关闭。
- DIP(依赖倒转原则): 要针对接口编程,不要针对实现编程。
- LoD(迪米特法则): 只与你的直接朋友通信,避免和陌生人通信。
- 简单工厂模式:(简单且常用)
//在没有工厂模式的情况下
public class Client01 {
public static void main(String[] args) {
Car c1 = new Audi();
Car c2 = new Byd();
c1.run();
c2.run();
}
}
public class CarFactory {
public Car createCar(String type){
if ("audi".equals(type)){
return new Audi();
}else if ("biyadi".equals(type)){
return new Byd();
}else
return null;
}
}
//在有简单工厂模式的情况下
public class Client01 {
public static void main(String[] args) {
Car c1 = CarFactory.createCar("audi");
Car c2 = CarFactory.createCar("biyadi");
c1.run();
c2.run();
}
}
这个时候client只需要知道两个东西就行了。
但是如果想增加新的接口一定要修改已有的方法代码,这是违反开闭原则的。
- 工厂方法模式
public interface CarFactory {
Car createCar();
}
public class AudiFactory implements CarFactory{
@Override
public Car createCar() {
return new Audi();
}
}
public class BydFactory implements CarFactory{
@Override
public Car createCar() {
return new Byd();
}
}
//在有简单工厂模式的情况下
public class Client01 {
public static void main(String[] args) {
Car c1 = new AudiFactory().createCar();
Car c2 = new BydFactory().createCar();
c1.run();
c2.run();
}
}
扩展的时候只需要增加新类来扩展,不需要修改代码。
- 抽象工厂模式:
package com.example.annotation.bean;
public interface Engine{
void run();
void start();
}
class LuxuryEngine implements Engine{
@Override
public void run() {
System.out.println("转的快");
}
@Override
public void start() {
System.out.println("启动快");
}
}
class LowEngine implements Engine{
@Override
public void run() {
System.out.println("转的慢");
}
@Override
public void start() {
System.out.println("启动慢");
}
}
package com.example.annotation.bean;
public interface Seat {
void massage();
}
class LuxurySeat implements Seat{
@Override
public void massage() {
System.out.println("可以按摩");
}
}
class LowSeat implements Seat{
@Override
public void massage() {
System.out.println("不可以按摩");
}
}
package com.example.annotation.bean;
public interface Tyre {
void revolve();
}
class LuxuryTyre implements Tyre{
@Override
public void revolve() {
System.out.println("转的快");
}
}
class LowTyre implements Tyre{
@Override
public void revolve() {
System.out.println("转的慢");
}
}
package com.example.annotation.bean;
public interface CarFactory {
Engine createEngine();
Seat createSeat();
Tyre createTyre();
}
class LuxuryCarFactory implements CarFactory{
@Override
public Engine createEngine() {
return new LuxuryEngine();
}
@Override
public Seat createSeat() {
return new LuxurySeat();
}
@Override
public Tyre createTyre() {
return new LuxuryTyre();
}
}
class LowCarFactory implements CarFactory{
@Override
public Engine createEngine() {
return new LowEngine();
}
@Override
public Seat createSeat() {
return new LowSeat();
}
@Override
public Tyre createTyre() {
return new LowTyre();
}
}
package com.example.annotation.bean;
//在有简单工厂模式的情况下
public class Client01 {
public static void main(String[] args) {
CarFactory factory = new LuxuryCarFactory();
Engine e = factory.createEngine();
e.run();
e.start();
}
}
3. 建造者模式
我们要建造一个复杂的产品,装配这些子组件有一个步骤顺序的问题。
本质上分离了对象子组件的单独构造(由Builder负责)和装配(由Director负责),从而可以构建出复杂的对象。适用于某个对象的构建过程复杂的情况下使用。
//宇宙飞船
public class AirShip {
private OrbitalModule orbitalModule; //轨道舱
private Engine engine; //发动机
private EscapeTower escapeTower; //逃离塔
public void launch(){
System.out.println("发射");
}
public OrbitalModule getOrbitalModule() {
return orbitalModule;
}
public void setOrbitalModule(OrbitalModule orbitalModule) {
this.orbitalModule = orbitalModule;
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
public EscapeTower getEscapeTower() {
return escapeTower;
}
public void setEscapeTower(EscapeTower escapeTower) {
this.escapeTower = escapeTower;
}
}
class OrbitalModule {
private String name;
public OrbitalModule(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Engine{
private String name;
public Engine(String name){
this.name= name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class EscapeTower{
private String name;
public EscapeTower(String name){
this.name= name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface AirShipBuilder {
OrbitalModule builderOrbitalModule();
Engine builderEngine();
EscapeTower builderEscapeTower();
}
public interface AirShipDirector {
//组装飞船对象
AirShip directAirShip();
}
public class NeuAirshipDirector implements AirShipDirector{
private AirShipBuilder builder;
public NeuAirshipDirector(AirShipBuilder builder) {
this.builder = builder;
}
@Override
public AirShip directAirShip() {
OrbitalModule o = builder.builderOrbitalModule();
Engine e = builder.builderEngine();
EscapeTower et = builder.builderEscapeTower();
//组装
AirShip ship = new AirShip();
ship.setOrbitalModule(o);
ship.setEngine(e);
ship.setEscapeTower(et);
return ship;
}
}
public class NeuAirShipBuilder implements AirShipBuilder{
@Override
public OrbitalModule builderOrbitalModule() {
System.out.println("构建轨道舱");
return new OrbitalModule("轨道舱");
}
@Override
public Engine builderEngine() {
System.out.println("构建发动机");
return new Engine("发动机");
}
@Override
public EscapeTower builderEscapeTower() {
System.out.println("构造逃逸塔");
return new EscapeTower("逃逸塔");
}
}
public class Client {
public static void main(String[] args) {
AirShipDirector director = new NeuAirshipDirector(new NeuAirShipBuilder());
AirShip ship = director.directAirShip();
System.out.println(ship.getEngine().getName());
ship.launch();
}
}
4. 原型模式 prototype
新建对象(new)很耗时,以某个对象为原型复制出新的对象效率更高。
实现方法:Cloneable接口和clone方法
public class Sheep implements Cloneable{
private String sname;
private Date birthday;
public Sheep(String sname, Date date) {
this.sname = sname;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException{
Object obj = super.clone(); //直接调用Object的克隆方法
return obj;
}
}
//浅克隆
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep s1 = new Sheep("dkm",new Date());
System.out.println(s1); //com.example.annotation.sjms.prototype.Sheep@5caf905d
Sheep s2 = (Sheep) s1.clone();
System.out.println(s2); //com.example.annotation.sjms.prototype.Sheep@27716f4
System.out.println(s1.getSname()); //dkm
System.out.println(s2.getSname()); //dkm
s2.setSname("xzq");
System.out.println(s2.getSname()); //xzq
}
}
两者指向的同一个date对象,当一个变了另一个也会变。这是因为只克隆了地址。
@Override
protected Object clone() throws CloneNotSupportedException{
Object obj = super.clone(); //直接调用Object的克隆方法
//添加如下代码实现深复制
Sheep s = (Sheep) obj;
s.birthday = (Date) this.birthday.clone();
return obj;
}
修改了之后引用的类就不会一样了。
5. 适配器模式(adapter)
将一个类的接口转换成客户希望的另外一个接口,Adapter使得原本由于接口不兼容而不能一起工作的类可以在一起工作。
包括:需要适配的类(adaptee),目标接口(Target),适配器(Adapter)
//相当于键盘
public class Adpatee {
public void request(){
System.out.println("可以完成客户请求的功能");
}
}
//适配器本身(类)
public class Adapter extends Adpatee implements Target {
@Override
public void handleReq() {
super.request();
}
}
public interface Target {
void handleReq();
}
//相当于笔记本,只有usb接口
public class Client {
public void test1(Target t){
t.handleReq();
}
public static void main(String[] args) {
Client c = new Client();
Adpatee a = new Adpatee();
Target t = new Adapter();
c.test1(t); //可以完成客户请求的功能
}
}
这是类适配方式,但是类是单继承的所以不够灵活
//适配器使用组合的方式跟被试陪对象整合
public class Adapter2 extends Adpatee implements Target {
private Adpatee adpatee;
@Override
public void handleReq() {
adpatee.request();
}
public Adapter2(Adpatee adpatee) {
this.adpatee = adpatee;
}
}
//相当于笔记本,只有usb接口
public class Client {
public void test1(Target t){
t.handleReq();
}
public static void main(String[] args) {
Client c = new Client();
Adpatee a = new Adpatee();
Target t = new Adapter2(a);
c.test1(t); //可以完成客户请求的功能
}
}
6. 代理模式(Proxy)
通过代理控制对对象的访问。是AOP(面向切面编程)的核心实现机制。
真实角色:明星(周杰伦)
代理角色:经纪人
抽象角色:定义代理角色和真实角色的公共对外方法
将统一的流程控制放在代理角色中处理。
- 静态代理(静态定义代理类)
//抽象角色
public interface Star {
//面谈
void confer();
//签合同
void signContract();
void bookTicket();
void sing();
//收钱
void collectMoney();
}
//真实类
public class RealStar implements Star{
@Override
public void confer() {
System.out.println("真实角色");
}
@Override
public void signContract() {
System.out.println("真实角色");
}
@Override
public void bookTicket() {
System.out.println("真实角色");
}
@Override
public void sing() {
System.out.println("真实角色唱歌");
}
@Override
public void collectMoney() {
System.out.println("真实角色");
}
}
//代理类
public class ProxyStar implements Star{
private Star star;
public ProxyStar(Star star) {
this.star = star;
}
@Override
public void confer() {
System.out.println("代理角色");
}
@Override
public void signContract() {
System.out.println("代理角色");
}
@Override
public void bookTicket() {
System.out.println("代理角色");
}
@Override
public void sing() {
star.sing();
}
@Override
public void collectMoney() {
System.out.println("代理角色");
}
}
public class Client {
public static void main(String[] args) {
Star real = new RealStar();
Star proxy = new ProxyStar(real);
proxy.confer(); //代理角色
proxy.signContract(); //代理角色
proxy.sing(); //真实角色唱歌
proxy.collectMoney(); //代理角色
}
}
- 动态代理(dynamic proxy)动态生成代理类
代理类交给工具生成。
自带的:java.lang.reflect.Proxy(动态生成代理类和对象),java.lang.reflect.InvocationHandler(处理器接口:可以通过invoke方法实现对真实角色的访问,每次通过Proxy生成代理类对象时都要指定对应的处理器对象)
//抽象角色
public interface Star {
//面谈
void confer();
//签合同
void signContract();
void bookTicket();
void sing();
//收钱
void collectMoney();
}
//真实类
public class RealStar implements Star {
@Override
public void confer() {
System.out.println("真实角色");
}
@Override
public void signContract() {
System.out.println("真实角色");
}
@Override
public void bookTicket() {
System.out.println("真实角色");
}
@Override
public void sing() {
System.out.println("真实角色唱歌");
}
@Override
public void collectMoney() {
System.out.println("真实角色");
}
}
public class StarHandler implements InvocationHandler {
Star realStar;
public StarHandler(Star realStar) {
this.realStar = realStar;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null;
System.out.println("面谈,签合同,等等等");
if (method.getName().equals("sing")){
object = method.invoke(realStar,args);
}
System.out.println("结束后收尾款等等");
return object;
}
}
public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class},handler);
proxy.sing();
//面谈,签合同,等等等
//真实角色唱歌
//结束后收尾款等等
}
}
- 动态代理内存调用过程
7. 桥接模式
多层继承结构。
public interface Computer {
void sale();
}
class Desktop implements Computer{
@Override
public void sale() {
System.out.println("销售台式机");
}
}
class Laptop implements Computer{
@Override
public void sale() {
System.out.println("销售笔记本");
}
}
class LenovoDesktop extends Desktop{
@Override
public void sale(){
System.out.println("销售联想台式机");
}
}
class LenovoLaptop extends Laptop{
@Override
public void sale(){
System.out.println("销售联想笔记本");
}
}
class SzDesktop extends Desktop{
@Override
public void sale(){
System.out.println("销售神州台式机");
}
}
class SzLaptop extends Laptop{
@Override
public void sale(){
System.out.println("销售神州笔记本");
}
}
未使用桥接模式
增加子类特别繁琐,可扩展性有问题。增加新的品牌或者新的电脑类型都很繁琐。这里每个类都承载了两个职责(类型和品牌)违反了单一职责的原则。
桥接模式:将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。
//品牌维度
public interface Brand {
void sale();
}
class Lenovo implements Brand {
@Override
public void sale() {
System.out.println("销售联想电脑");
}
}
class Dell implements Brand {
@Override
public void sale() {
System.out.println("销售戴尔电脑");
}
}
//电脑类型维度
public class Computer2 {
protected Brand brand;
Computer2(Brand b){
this.brand = b;
}
public void sale(){
brand.sale();
}
}
class Desktop2 extends Computer2 {
public Desktop2(Brand b) {
super(b);
}
@Override
public void sale(){
super.sale();
System.out.println("销售台式机");
}
}
class Laptop2 extends Computer2 {
public Laptop2(Brand b) {
super(b);
}
@Override
public void sale(){
super.sale();
System.out.println("销售笔记本");
}
}
public class Client {
public static void main(String[] args) {
//销售联想的笔记本电脑
Computer2 c = new Laptop2(new Lenovo());
c.sale();
//销售联想电脑
//销售笔记本
}
}
这样无论是扩展品牌还是电脑类型都可以只修改一个地方。可以用来取代多层继承结构。
8. 组合模式(composite)
经常由于处理树形的结构。分为抽象构建,容器和叶子。
public interface Component {
void operation();
}
//叶子组件
interface Leaf extends Component {
}
//容器组件
interface Composite extends Component{
void add(Component c);
void remove(Component c);
Component getChile(int index);
}
public interface Component {
void operation();
}
//叶子组件
interface Leaf extends Component {
}
//容器组件
interface Composite extends Component{
void add(Component c);
void remove(Component c);
Component getChile(int index);
}
//抽象构建
public interface AbstractFile {
void killVirus(); // 杀毒
}
//叶子组件
class ImageFile implements AbstractFile {
private String name;
public ImageFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("--图像文件: " + name);
}
}
//叶子组件
class TextFile implements AbstractFile {
private String name;
public TextFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("--文本文件: " + name);
}
}
//容器组件
class Folder implements AbstractFile {
private String name;
//定义容器用来存储子节点
private List<AbstractFile> list = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(AbstractFile file){
list.add(file);
}
public void remove(AbstractFile file){
list.remove(file);
}
public AbstractFile get(int index){
return list.get(index);
}
@Override
public void killVirus() {
System.out.println("---文件夹: " + name );
for (AbstractFile file : list){
file.killVirus();
}
}
}
public class Client {
public static void main(String[] args) {
Folder f1;
AbstractFile f2,f3;
f1 = new Folder("我的收藏");
f2 = new ImageFile("lalala.jpg");
f3 = new TextFile("hello.txt");
f1.add(f2);
f1.add(f3);
f1.killVirus();
//---文件夹: 我的收藏
//--图像文件: lalala.jpg
//--文本文件: hello.txt
f2.killVirus();
//--图像文件: lalala.jpg
f3.killVirus();
//--文本文件: hello.txt
}
}
树状结构往往都要用到组合模式。
更多推荐
【JAVA学习】六、设计模式
发布评论