OOP七大原则
- 开闭原则:对扩展开放,对修改关闭
- 里氏替换原则:继承必须确保超类所拥有的性质在子类中仍然成立
- 依赖倒置原则:面向接口编程,不要面向实现编程
- 单一职责原则:控制类的粒度大小,将对象解耦,提高其内聚性
- 接口隔离原则:要为各个类建立他们所需要的专用接口
- 迪米特法则: 只和你的直接朋友交谈,不跟陌生人说话
- 合成复用原则;尽量先使用组合或者聚合的关系来实现,其次才使用继承关系来实现
工厂模式
核心: 实例化对象不使用new ,用工厂方法代替。
将选择实类,创建对象统一管理和控制,从而将我们的实现类解耦
三种模式 :
- 简单工厂模式
用来生产同等级结构中的任意产品,虽然在某种程度上不符合设计原则,但是实际使用最多 - 工厂方法模式
用来生产同一等级结构中的固定产品,不修改已有类的前提下增加新工厂来实现扩展 - 抽象工厂模式
围绕一个超级工厂来创建其它工厂,该超级工厂又称为其他工厂的工厂
应用场景
- JDK中Calender的getInstance()方法
- JDBC中的connection对象获取
- Spring中IOC容器创建管理bean对象
- 反射中的CLass对象newInstance方法
现在假设顾客想买一辆车
public interface Car {
//名称
void name();
}
public class TeSla implements Car{
@Override
public void name() {
System.out.println("这是特斯拉");
}
}
public class BaoMa implements Car{
@Override
public void name() {
System.out.println("这是宝马");
}
}
顾客想获得一辆车,我们的正常思路为 new 对象然后调用方法
BaoMa baoMa=new BaoMa();
TeSla teSla=new TeSla();
baoMa.name();
teSla.name();
这个未免显得有些繁琐,还得顾客去new 所以我们考虑可不可以有一个工厂帮我们做这件事
这样好像可以了,但是仔细想一下有会有新的问题,假设我们需要另一种类型的汽车还得去修改代码,这就不符合七大原则之一的开闭原则,所以我们再来改进一下我们的代码。
public interface CarFactory {
//相当于汽车大工厂
Car getCar();
}
现在我们想要什么类型的车只需要实现接口然后从写方法就可以,不用将代码进行修改,只需要进行横向扩展即可。
抽象工厂模式
- 定义:抽象工厂模式提供了一个创建一系列相关或者相互依赖的对象的接口,无需指定它们具体的类
- 客户端不依赖产品类实例如何被创建,实现等细节
- 强调一系列相关的产品对象一起使用 创建对象 需要大量的重复代码
- 提供一系列产品的的库,所有产品以同样的接口出现从而客户端不依赖与具体的实现
代码演示
现在有两个工厂一个负责生产手机,一个负责生产路由器
//路由器工厂专门用于生产路由器
public interface RouterProduct {
void open();
void close();
void setMs();
}
//手机工厂专门生产手机
public interface phoneFactory {
void open();
void sendMessage();
void close();
}
还有一个总工厂负责这两个工厂的生产(有点抽象这样理解就好了)
public interface FactoryAll {
//生产手机
phoneFactory phoneProduct();
//生产路由器
RouterProduct routerProduct();
}
现在我们想生产一个华为手机,和一个华为路由器 ok实现总工厂接口即可
public class huaweiFactory implements FactoryAll{
@Override
public phoneFactory phoneProduct() {
return new huaweiPhone();
}
@Override
public RouterProduct routerProduct() {
return new huaweiRouter();
}
}
ok我们现在可以拿着华为工厂生产华为产品了
- 华为手机
public class huaweiPhone implements phoneFactory{
@Override
public void open() {
System.out.println("华为手机开机");
}
@Override
public void sendMessage() {
System.out.println("华为手机发送信息");
}
@Override
public void close() {
System.out.println("华为手机关机");
}
}
- 华为路由器
public class huaweiRouter implements RouterProduct{
@Override
public void open() {
System.out.println("华为路由器开");
}
@Override
public void close() {
System.out.println("华为路由器关闭");
}
@Override
public void setMs() {
System.out.println("华为路由器修改参数");
}
}
模拟客户
public class Client {
@Test
public void getProduct(){
//得到工厂
huaweiFactory huaweiFactory=new huaweiFactory();
//想要工厂生产手机
phoneFactory phoneFactory = huaweiFactory.phoneProduct();
//手机
phoneFactory.open();
phoneFactory.sendMessage();
phoneFactory.close();
//想要路由器
RouterProduct routerProduct = huaweiFactory.routerProduct();
//路由器
routerProduct.open();
routerProduct.setMs();
routerProduct.close();
}
@Test
public void buy(){
System.out.println("我想看看华为产品");
getProduct();
}
}
这个就比较好理解了,我想要华为产品,那么我得到的产品都是由华为一个工厂生产的。
但是大家想一下如果客户想看一下华为机器人,怎么办厂家不仅要在总工厂中增加接口代码,而且要增加实现类,会大量修改代码,这样不就是他的缺点了吗
代理模式
- 介绍:
再比如我们王者荣耀的水平不够所以我们请代打来帮我们打游戏。
我们现在开始写代码
这里有一个演员接口,演员的职责就是表演(play)
public interface Actor {
//演员演电影
void play();
}
假设作者现在是一个小鲜肉
public class jiaSen implements Actor{
@Override
public void play() {
System.out.println("jiaSen想演一部记忆深刻的电影");
}
}
现在jiaSen找了一个经纪人
public class agent implements Actor{
private jiaSen jiaSen;
public agent(jiaSen jiaSen){
this.jiaSen=jiaSen;
}
//经纪人额外干的事情
public void link(){
System.out.println("经济人帮jiaSen联系公司找片方");
}
@Override
public void play() {
jiaSen.play();
link();
}
}
jiaSen现在演电影火了,所以经纪人想加钱了,但是呐jiaSen说可以但是又前提,你现在只能做我一个人的经纪人
不许做其它人的
经过协商 经纪人最后同意了
public agent(){
this.jiaSen=new jiaSen();
}
//加钱
public void addMoney(){
System.out.println("加1000块钱");
}
在别人看了经纪人是透明的。。
动态代理
- 然而好景不长,经纪人太贪了jiaSen感觉自己挣得钱越来越少了,想找其他经纪人又害怕比这个更贪
- 所以jiaSen决定合理的规划自己的时间决定自己当自己的经济人。
public static void main(String[] args) {
jiaSen jiaSen=new jiaSen();
Actor proxyInstance = (Actor) Proxy.newProxyInstance(jiaSen.getClass().getClassLoader(), jiaSen.getClass().getInterfaces(),
(proxy, method, args1) -> {
if (method.getName().equals("play")){
method.invoke(jiaSen,args);
System.out.println("jiaSen抽出时间来自己当代理人");
}else{
return method.invoke(jiaSen,args);
}
return null;
});
proxyInstance.play();
}
我们来解读一下这段代码
- Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,该方法需要三个参数
动态代理与静态代理的区别
- 静态代理需要写自己的代理类==>代理类和被代理类实现相同的接口
- 动态代理通过反射机制动态生成
静态代理缺点:
- 如果接口中有很多方法的时候每一个方法都得实现未免有些麻烦与繁琐
动态代理优点
- 代理对象的生成,是利用JDKAPI,动态的在内存中构建代理对象,并且会默认实现接口的全部方法