继续创作,加快成长!这是我参加「日新计划 10 月更文挑战」的第7天,点击查看活动概况

前言

很快乐遇见你~

规划形式是咱们编程的根底,把握好常用的规划形式,能让咱们写出可扩展,可维护,可复用的高质量代码。

一、什么是规划形式?

规划形式是被广泛运用,软件开发者编码经历的一个总结。运用规划形式的意图是为了让咱们写出来的代码更简略被别人了解,具有高可复用性,可扩展性和可维护性

二、规划形式遵循的六大准则

2.1、开闭准则

简略了解:对扩展敞开,对修正关闭

开闭准则是最根底的一个准则,其他 5 个准则都是开闭准则的详细形状,而开闭准则才是真正的精神领袖

举个书店卖书的比如:

//1、界说书本的接口
interface IBook {
    //称号
    String getName();
    //价格
    int getPrice();
    //作则
    String getAuthor();
}
//2、详细完结类:小说书
class NovelBook implements IBook{
    private final String name;
    private final int price;
    private final String author;
    public NovelBook(String name, int price, String author) {
        this.name = name;
        this.price = price;
        this.author = author;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public int getPrice() {
        return price;
    }
    @Override
    public String getAuthor() {
        return author;
    }
}
//3、书店,模拟卖书
public class BookStore {
    private final static List<IBook> BOOK_LIST = new ArrayList<>();
    static {
        BOOK_LIST.add(new NovelBook("天龙八部", 3200, "金庸"));
        BOOK_LIST.add(new NovelBook("巴黎圣母院", 3300, "雨果"));
        BOOK_LIST.add(new NovelBook("悲惨世界", 3400, "雨果"));
        BOOK_LIST.add(new NovelBook("水浒传", 3500, "施耐庵"));
    }
    public static void main(String[] args) {
        NumberFormat numberFormat = NumberFormat.getCurrencyInstance();
        numberFormat.setMaximumFractionDigits(2);
        System.out.println("书店卖出的书本如下: ");
        for (IBook book : BOOK_LIST) {
            System.out.println("书本称号: " + book.getName() 
                               + "\t书本作者: " + book.getAuthor() 
                               + "\t书本价格: " + numberFormat.format(book.getPrice() / 100) + "元");
        }
    }
}
//打印成果
书店卖出的书本如下: 
书本称号: 天龙八部	书本作者: 金庸	书本价格: ¥32.00元
书本称号: 巴黎圣母院	书本作者: 雨果	书本价格: ¥33.00元
书本称号: 悲惨世界	书本作者: 雨果	书本价格: ¥34.00元
书本称号: 水浒传	书本作者: 施耐庵	书本价格: ¥35.00

上面的代码咱们就完结了书店模拟买书的状况,可是假如我要搞个打折活动,上面的功用是不支持的,因而咱们需求对程序去扩展,如下:

//继承当前书本的完结类,对获取价格的办法进行修正打折
class OffNovelBook extends NovelBook{
    public OffNovelBook(String name, int price, String author) {
        super(name, price, author);
    }
    @Override
    public int getPrice() {
        int originPrice = super.getPrice();
        int offPrice = 0;
      	//大于 34 块,打 8 折,不然打 9 折
        if(originPrice > 3400){
            offPrice = (int) (originPrice * 0.8);
        }else {
            offPrice = (int) (originPrice * 0.9);
        }
        return offPrice;
    }
}
public class BookStore {
    private final static List<IBook> BOOK_LIST = new ArrayList<>();
    static {
        BOOK_LIST.add(new OffNovelBook("天龙八部", 3200, "金庸"));
        BOOK_LIST.add(new OffNovelBook("巴黎圣母院", 3300, "雨果"));
        BOOK_LIST.add(new OffNovelBook("悲惨世界", 3400, "雨果"));
        BOOK_LIST.add(new OffNovelBook("水浒传", 3500, "施耐庵"));
    }
    public static void main(String[] args) {
        NumberFormat numberFormat = NumberFormat.getCurrencyInstance();
        numberFormat.setMaximumFractionDigits(2);
        System.out.println("书店卖出的书本如下: ");
        for (IBook book : BOOK_LIST) {
            System.out.println("书本称号: " + book.getName() + "\t书本作者: " + book.getAuthor() + "\t书本价格: " + numberFormat.format(book.getPrice() / 100) + "元");
        }
    }
}
//打印成果
书店卖出的书本如下: 
书本称号: 天龙八部	书本作者: 金庸	书本价格: ¥28.00元
书本称号: 巴黎圣母院	书本作者: 雨果	书本价格: ¥29.00元
书本称号: 悲惨世界	书本作者: 雨果	书本价格: ¥30.00元
书本称号: 水浒传	书本作者: 施耐庵	书本价格: ¥28.00

2.2、里氏替换准则

简略了解:运用基类的地方能够运用子类替换

以战士拿枪击杀敌人为例:

//1、定一一个运用枪的接口
interface AbstractGun {
    void shoot();
}
//2、详细完结1:手枪
class HandGun implements AbstractGun{
    @Override
    public void shoot() {
        System.out.println("手枪射击");
    }
}
//3、详细完结2:机枪
class MachineGun implements AbstractGun{
    @Override
    public void shoot() {
        System.out.println("机枪射击");
    }
}
//3、详细完结3:步枪
class RifleGun implements AbstractGun{
    @Override
    public void shoot() {
        System.out.println("步枪射击");
    }
}
//4、界说一个战士 
class Soldier {
    //持有的枪
    private AbstractGun gun;
    //设置枪
    public void setAbstractGun(AbstractGun gun){
        this.gun = gun;
    }
    //击杀敌人
    public void killEnemy(){
        System.out.println("开端kill敌人");
        this.gun.shoot();
    }
}
//5、客户端测验类
public class Client {
    public static void main(String[] args) {
      	//创立一个战士的实例
        Soldier soldier = new Soldier();
      	//设置枪 基类存在的地方能够用子类替换详细体现
        soldier.setAbstractGun(new HandGun());
      	//击杀敌人
        soldier.killEnemy();
    }
}
//打印成果
开端kill敌人
手枪射击

UML类图如下:

2.3、依靠倒置准则

简略了解:面向接口编程

举个司机开车的比如:

//界说一个开车的接口
interface ICar {
    /**
     * 开车
     */
    void run();
}
//界说一个开车的司机接口
interface IDriver {
    /**
     * 开车
     * @param iCar ICar接口
     */
    void driver(ICar iCar);
}
//开车的详细完结类1
class Benz implements ICar{
    @Override
    public void run() {
        System.out.println("开奔驰车");
    }
}
//开车的详细完结类1
class BWM implements ICar{
    @Override
    public void run() {
        System.out.println("开宝马车");
    }
}
//司机的详细完结类
class Driver implements IDriver{
    @Override
    public void driver(ICar iCar) {
        iCar.run();
    }
}
//测验类
public class Client {
    public static void main(String[] args) {
      	//界说接口引证,详细完结则是对应接口的完结类,这便是面向接口编程,即多态,完结类之间不直接发生依靠关系
        IDriver iDriver = new Driver();
        ICar benz = new Benz();
        iDriver.driver(benz);
    }
}
//打印成果
开奔驰车

2.4、迪米特规律

简略了解:一个方针对另一个方针应该尽可能少的了解

例如:教师指令班长清点学生人数,那么教师只有和班长有交流,下达这个指令给班长,其他的工作交给班长做就行了,详细完结:

//学生
class Student {
}
//班长
class ClassLeader {
    private final List<Student> studentList;
    public ClassLeader(List<Student> studentList) {
        this.studentList = studentList;
    }
    //清点学生人数
    public void countStudentList(){
        System.out.println("学生的人数是: " + studentList.size());
    }
}
//教师
class Teacher {
    //下达指令给班长
    public void command(ClassLeader classLeader){
        classLeader.countStudentList();
    }
}
//测验类
public class Client {
    public static void main(String[] args) {
        List<Student> studentList = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            studentList.add(new Student());
        }
        ClassLeader classLeader = new ClassLeader(studentList);
        Teacher teacher = new Teacher();
        teacher.command(classLeader);
    }
}
//打印成果
学生的人数是: 20

2.5、接口阻隔准则

简略了解:运用多个接口,比运用单个接口要好

例如:每个人的审美观不一样,张三以为颜值高便是美人,即使身段和气质一般;李四以为身段好就行,不在乎颜值和气质;而王五则以为颜值和身段都是外在,只要有气质,那便是美人。这时,咱们就要分开的去界说接口了,代码完结:

//颜值高
interface IGoodLookingGirl {
    void goodLooking();
}
//气质拔尖
interface IGreatTemperamentGirl {
    void greatTemperament();
}
//身段好
interface INiceFigureGirl {
    void niceFigure();
}
//详细完结类
class PrettyGirl implements IGoodLookingGirl,IGreatTemperamentGirl,INiceFigureGirl{
    private String name;
    public PrettyGirl(String name) {
        this.name = name;
    }
    @Override
    public void goodLooking() {
        System.out.println(this.name + "颜值很高");
    }
    @Override
    public void greatTemperament() {
        System.out.println(this.name + "气质拔尖");
    }
    @Override
    public void niceFigure() {
        System.out.println(this.name + "身段很好");
    }
}
//查找笼统类
abstract class AbstractSearcher {
    protected IGoodLookingGirl goodLookingGirl;
    protected IGreatTemperamentGirl greatTemperamentGirl;
    protected INiceFigureGirl niceFigureGirl;
    public AbstractSearcher(IGoodLookingGirl goodLookingGirl, IGreatTemperamentGirl greatTemperamentGirl, INiceFigureGirl niceFigureGirl) {
        this.goodLookingGirl = goodLookingGirl;
        this.greatTemperamentGirl = greatTemperamentGirl;
        this.niceFigureGirl = niceFigureGirl;
    }
    public abstract void show();
}
//详细查找完结
class Searcher extends AbstractSearcher {
public Searcher(IGoodLookingGirl goodLookingGirl, IGreatTemperamentGirl greatTemperamentGirl, INiceFigureGirl 	niceFigureGirl) {
        super(goodLookingGirl, greatTemperamentGirl, niceFigureGirl);
 }
    @Override
    public void show() {
        System.out.println("美人信息如下: ");
        if(super.goodLookingGirl != null)
        super.goodLookingGirl.goodLooking();
        if(super.niceFigureGirl != null)
        super.niceFigureGirl.niceFigure();
        if(super.greatTemperamentGirl != null)
        super.greatTemperamentGirl.greatTemperament();
    }
}
//测验类
public class Client {
   public static void main(String[] args) {
      PrettyGirl prettyGirl = new PrettyGirl("lily");
      Searcher searcher = new Searcher(prettyGirl,prettyGirl,null);
      searcher.show();
   }
}
//打印成果
美人信息如下: 
lily颜值很高
lily气质拔尖

2.6、单一责任准则

简略了解:一个类或接口只担任一件工作

例如:以打电话为例,打电话大致流程分为:拨号,通话,挂断。咱们规划一个接口:

public interface IPhone {
    /**
     * 拨号
     */
    void dial();
    /**
     * 通话
     */
    void call();
    /**
     * 挂断
     */
    void hangUp();
}

上面这个接口规划看上去没什么问题,可是咱们详细分析一下,拨号和挂断归于协议衔接,通话归于数据传送,一个接口里边承当了两个责任,这是不符合单一责任的,因而咱们能够进行如下改造:

public interface IConnectionManage {
    /**
     * 拨号
     */
    void dial();
    /**
     * 挂断
     */
    void hangUp();
}
public interface IDataTransform {
    /**
     * 通话
     */
    void call();
}

将其拆分红两个接口,每个接口只承当一个责任,这样就完美了

三、常用的规划形式

3.1、工厂形式

工厂形式不是一种独自的规划形式,而是3种功用附近的规划形式的总称,如下:

为了方便了解,咱们以创立口罩为比如来阐明:

3.1.1、简略工厂形式

界说:简略工厂形式具有仅有的工厂类,工厂类依据传入的参数经过 if-else 条件判别决议去创立哪个产品

举例阐明:

咱们界说一个口罩的接口,它下面有高端口罩和低端口罩两种产品子类,现在咱们运用简略工厂形式去创立他们:

//界说一个口罩的接口
interface IMask{
    void show();
}
//口罩的详细完结,高端口罩
class HighMask implements IMask{
    @Override
    public void show() {
        System.out.println("我是高端口罩");
    }
}
//口罩的详细完结,低端口罩
class LowMask implements IMask{
    @Override
    public void show() {
        System.out.println("我是低端口罩");
    }
}
//简略工厂具有仅有的工厂类
class MaskFactory{
    public IMask createMask(String type){
        IMask mask = null;
        if("高端口罩".equals(type)){
            mask = new HighMask();
        }else if("低端口罩".equals(type)){
            mask = new LowMask();
        }
        return mask;
    }
}
//测验类
public class FactoryClient {
    public static void main(String[] args) {
        MaskFactory maskFactory = new MaskFactory();
        IMask mHighMask = maskFactory.createMask("高端口罩");
        IMask mLowMask = maskFactory.createMask("低端口罩");
        mHighMask.show();
        mLowMask.show();
    }
}
//打印成果
我是高端口罩
我是低端口罩

缺陷: 当我新增产品子类又要去新增if-else条件判别,不符合开闭准则,针对这种状况咱们能够运用工厂办法形式

3.1.2、工厂办法形式

界说:工厂办法形式具有多个工厂,利用多态去创立不同的产品方针,避免了简略工厂形式冗余的 if-else 条件判别

咱们给不同的产品子类创立一个对应的工厂:

//界说一个口罩的接口
interface IMask{
    void show();
}
//口罩的详细完结,高端口罩
class HighMask implements IMask{
    @Override
    public void show() {
        System.out.println("我是高端口罩");
    }
}
//口罩的详细完结,低端口罩
class LowMask implements IMask{
    @Override
    public void show() {
        System.out.println("我是低端口罩");
    }
}
//界说出产口罩的工厂接口
interface IMaskFactory{
    IMask createMask();
}
//高端口罩工厂类
class HighMaskFactory implements IMaskFactory{
    @Override
    public IMask createMask() {
        return new HighMask();
    }
}
//低端口罩工厂类
class LowMaskFactory implements IMaskFactory{
    @Override
    public IMask createMask() {
        return new LowMask();
    }
}
//测验类
public class FactoryClient {
    public static void main(String[] args) {
        IMaskFactory mHighMaskFactory = new HighMaskFactory();
        IMaskFactory mLowMaskFactory = new LowMaskFactory();
        IMask mHighMask = mHighMaskFactory.createMask();
        IMask mLowMask = mLowMaskFactory.createMask();
        mHighMask.show();
        mLowMask.show();
    }
}
//打印成果
我是高端口罩
我是低端口罩

缺陷: 当我新增的不同类型的产品,例如防护服,并且也分为高端防护服和低端防护服,依次类推,那么咱们针对这些产品子类都需求去创立一个工厂子类,工厂子类将会变的十分多,针对这种状况咱们能够运用笼统工厂形式

3.1.3、笼统工厂形式

界说:笼统工厂形式会把不同产品子类进行分组,组内不同的产品子类对应同一个工厂子类的不同创立办法,这样就削减了工厂子类的创立

例如咱们刚才说的,这个时分咱们又新增了高端防护服和低端防护服,那么这个时分咱们就能够划分高端产品和低端产品两个分组,高端产品包含高端口罩和高端防护服,低端产品包含低端口罩和低端防护服,针对这个产品分组,咱们就只需求创立高端工厂和低端工厂就ok了,这样就削减了工厂子类的创立:

//界说一个口罩的接口
interface IMask{
    void show();
}
//口罩的详细完结,高端口罩
class HighMask implements IMask{
    @Override
    public void show() {
        System.out.println("我是高端口罩");
    }
}
//口罩的详细完结,低端口罩
class LowMask implements IMask{
    @Override
    public void show() {
        System.out.println("我是低端口罩");
    }
}
//界说防护服的接口
interface IProtectiveSuit{
    void show();
}
//防护服的详细完结,高端防护服
class HighProtectiveSuit implements IProtectiveSuit{
    @Override
    public void show() {
        System.out.println("我是高端防护服");
    }
}
//防护服的详细完结,低端防护服
class LowProtectiveSuit implements IProtectiveSuit{
    @Override
    public void show() {
        System.out.println("我是低端防护服");
    }
}
//界说工厂接口
interface IFactory{
    IMask createMask();
    IProtectiveSuit createSuit();
}
//高端工厂
class HighFactory implements IFactory{
    @Override
    public IMask createMask() {
        return new HighMask();
    }
    @Override
    public IProtectiveSuit createSuit() {
        return new HighProtectiveSuit();
    }
}
//低端工厂
class LowFactory implements IFactory{
    @Override
    public IMask createMask() {
        return new LowMask();
    }
    @Override
    public IProtectiveSuit createSuit() {
        return new LowProtectiveSuit();
    }
}
//测验类
public class FactoryClient {
    public static void main(String[] args) {
        IFactory mHighFactory = new HighFactory();
        IFactory mLowFactory = new LowFactory();
        IMask mHighMask = mHighFactory.createMask();
        IProtectiveSuit mHighProtectiveSuit = mHighFactory.createSuit();
        IMask mLowMask = mLowFactory.createMask();
        IProtectiveSuit mLowProtectiveSuit = mLowFactory.createSuit();
        mHighMask.show();
        mHighProtectiveSuit.show();
        mLowMask.show();
        mLowProtectiveSuit.show();
    }
}
//打印成果
我是高端口罩
我是高端防护服
我是低端口罩
我是低端防护服

3.1.4、工厂办法形式和笼统工厂形式的异同

异:

1、工厂办法形式针对的是单个产品等级结构,而笼统工厂形式针对的是多个产品的等级结构

2、工厂办法形式每个详细的工厂只能创立一种产品方针,而笼统工厂形式的详细工厂能创立多个产品方针

同:

1、工厂办法形式和笼统工厂形式的笼统产品都具有多个详细的完结产品

2、工厂办法形式和笼统工厂形式的笼统工厂类都有多个详细的完结工厂类

3.2、战略形式

界说:界说一系列的算法,并能够完结自在的切换

举个古装大侠打架的比如:

//界说一个进犯招式的接口
interface IAttack{
    void attack();
}
//定一个笼统的人物类
abstract class Role{
    protected String name;
    private IAttack iAttack;
    public Role(String name) {
        this.name = name;
    }
    public void setiAttack(IAttack iAttack) {
        this.iAttack = iAttack;
    }
    public void attack(){
        iAttack.attack();
    }
}
//详细人物类
class MyRole extends Role{
    public MyRole(String name) {
        super(name);
    }
}
//进犯招式的详细完结
class MyAttack implements IAttack{
    @Override
    public void attack() {
        System.out.println("降龙十八掌");
    }
}
//进犯招式的详细完结
class MyAttack2 implements IAttack{
    @Override
    public void attack() {
        System.out.println("天地大移动");
    }
}
//测验类
public class StrategyClient2 {
    public static void main(String[] args) {
        MyRole myRole = new MyRole("乔峰");
        myRole.setiAttack(new MyAttack());
      	//详细运用什么招式进犯 由客户端自己决议
      	//myRole.setiAttack(new MyAttack2());
        System.out.println(myRole.name + ": ");
        myRole.attack();
    }
}
//打印成果
乔峰: 
降龙十八掌

3.3、状况形式

界说:方针内部状况的改动会改动其行为

举个电视机开关机的比如:

//界说电视机的状况
interface TvState{
    void nextChannel();
    void prevChannel();
    void turnUp();
    void turnDown();
}
//详细完结 关机状况
class PowerOfferState implements TvState{
    @Override
    public void nextChannel() {
    }
    @Override
    public void prevChannel() {
    }
    @Override
    public void turnUp() {
    }
    @Override
    public void turnDown() {
    }
}
//详细完结 开机状况
class PowerOnState implements TvState{
    @Override
    public void nextChannel() {
        System.out.println("下一个频道");
    }
    @Override
    public void prevChannel() {
        System.out.println("上一个频道");
    }
    @Override
    public void turnUp() {
        System.out.println("调高音量");
    }
    @Override
    public void turnDown() {
        System.out.println("调低音量");
    }
}
//电源接口
interface PowerController{
    void powerOff();
    void powerOn();
}
//电视遥控器
class TvController implements PowerController{
    private TvState tvState;
    public void setTvState(TvState tvState) {
        this.tvState = tvState;
    }
    @Override
    public void powerOff() {
        setTvState(new PowerOfferState());
        System.out.println("关机了");
    }
    @Override
    public void powerOn() {
        setTvState(new PowerOnState());
        System.out.println("开机了");
    }
    public void nextChannel() {
        tvState.nextChannel();
    }
    public void prevChannel() {
        tvState.prevChannel();
    }
    public void turnUp() {
        tvState.turnUp();
    }
    public void turnDown() {
        tvState.turnDown();
    }
}
//测验类
public class StateClient {
    public static void main(String[] args) {
        TvController tvController = new TvController();
        tvController.powerOn();
        tvController.nextChannel();
        tvController.turnUp();
        tvController.powerOff();
        tvController.turnUp();
        tvController.prevChannel();
        tvController.turnDown();
    }
}
//打印成果
开机了
下一个频道
调高音量
关机了

3.4、署理形式

署理形式首要是运用署理方针绑架原始方针,到达对原始方针的控制

署理形式分为:

1、静态署理

2、动态署理

3.4.1、静态署理

//1、界说一个署理接口
public interface ITestProxy {
    void test();
    void login();
    void register();
}
//2、完结类
public class TestProxy implements ITestProxy{
    @Override
    public void test(){
        System.out.println("被署理方针执行了 test 办法");
    }
    @Override
    public void login() {
        System.out.println("被署理方针执行了 login 办法");
    }
    @Override
    public void register() {
        System.out.println("被署理方针执行了 register 办法");
    }
}
//3、署理类
public class StaticProxy implements ITestProxy{
    private final ITestProxy testProxy;
    public StaticProxy(ITestProxy testProxy) {
        this.testProxy = testProxy;
    }
    @Override
    public void test(){
        System.out.println("testBefore...");
        testProxy.test();
        System.out.println("testAfter...");
    }
    @Override
    public void login() {
        System.out.println("loginBefore...");
        testProxy.login();
        System.out.println("loginAfter...");
    }
    @Override
    public void register() {
        testProxy.register();
    }
}
//4、测验
public class Client {
    public static void main(String[] args) {
        //静态署理
        TestProxy testProxy = new TestProxy();
        StaticProxy staticProxy = new StaticProxy(testProxy);
        staticProxy.test();
        staticProxy.login();
        staticProxy.register();
    }
}
//打印成果
testBefore...
被署理方针执行了 test 办法
testAfter...
loginBefore...
被署理方针执行了 login 办法
loginAfter...
被署理方针执行了 register 办法

能够看到,上述咱们运用署理方针 StaticProxy 绑架了原始方针 TestProxy,并插入了一些 log 打印

3.4.2、动态署理

动态署理首要分两种:

1、JDK 动态署理

2、cglib 动态署理

3.4.2.1、JDK 动态署理
//1、界说一个署理接口
public interface ITestProxy {
    void test();
    void login();
    void register();
}
//2、完结类
public class TestProxy implements ITestProxy{
    @Override
    public void test(){
        System.out.println("被署理方针执行了 test 办法");
    }
    @Override
    public void login() {
        System.out.println("被署理方针执行了 login 办法");
    }
    @Override
    public void register() {
        System.out.println("被署理方针执行了 register 办法");
    }
}
//3、界说一个动态署理 Handler
public class LogHandler implements InvocationHandler {
    final Object target;
    public LogHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("test".equals(method.getName())){
            System.out.println("testBefore...");
            Object invoke = method.invoke(target, args);
            System.out.println("testAfter...");
            return invoke;
        }else if("login".equals(method.getName())){
            System.out.println("loginBefore...");
            Object invoke = method.invoke(target, args);
            System.out.println("loginAfter...");
            return invoke;
        }
        return method.invoke(target,args);
    }
}
//4、测验
public class Client {
    public static void main(String[] args) {
        //JDK 动态署理
        ClassLoader classLoader = ITestProxy.class.getClassLoader();
        Class<?>[] interfaces = new Class[]{ITestProxy.class};
      	//动态署理方针
        ITestProxy iTestProxy = (ITestProxy) Proxy.newProxyInstance(classLoader, interfaces, new LogHandler(new TestProxy()));
        iTestProxy.test();
        iTestProxy.login();
        iTestProxy.register();
    }
//打印成果
testBefore...
被署理方针执行了 test 办法
testAfter...
loginBefore...
被署理方针执行了 login 办法
loginAfter...
被署理方针执行了 register 办法

动态署理运用起来比较简略,要害办法是:java.langlreflect包下的 ProxynewProxyInstance办法

别的需求留意JDK 动态署理中被署理方针必须要完结一个接口。假如有一个需求被署理的方针没有完结接口,那么它就署理不了

假如我想完结被署理方针没有完结接口的这种办法要怎么办呢?

答:运用 cglib 动态署理

3.4.2.2、cglib 动态署理

首先咱们需求进入,cglib 这个库:

implementation 'cglib:cglib:3.2.6'

接着来进行详细完结:

//1、界说一个需求被署理方针,能够看到 TestProxy 没有完结任何接口
public class TestProxy{
    public void test(){
        System.out.println("被署理方针执行了 test 办法");
    }
    public void login() {
        System.out.println("被署理方针执行了 login 办法");
    }
    public void register() {
        System.out.println("被署理方针执行了 register 办法");
    }
}
//2、界说 cglib 署理类
public class CglibProxy implements MethodInterceptor {
    //被署理方针
    private final Object object;
    public CglibProxy(Object object) {
        this.object = object;
    }
    public Object getProxyInstance(){
        //东西类
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(object.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //常见署理方针并返回
        return enhancer.create();
    }
    @Override
    public Object intercept(Object proxyObject, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if("test".equals(method.getName())){
            System.out.println("testBefore...");
            Object invoke = method.invoke(object, args);
            System.out.println("testAfter...");
            return invoke;
        }else if("login".equals(method.getName())){
            System.out.println("loginBefore...");
            Object invoke = method.invoke(object, args);
            System.out.println("loginAfter...");
            return invoke;
        }
        return method.invoke(object,args);
    }
}
//3、测验
public class Client {
    public static void main(String[] args) {
        //cglib 动态署理
        TestProxy testProxy = new TestProxy();
        final TestProxy cgLibTestProxy = (TestProxy) new CglibProxy(testProxy).getProxyInstance();
        cgLibTestProxy.test();
        cgLibTestProxy.login();
        cgLibTestProxy.register();
    }
}
//打印成果
testBefore...
被署理方针执行了 test 办法
testAfter...
loginBefore...
被署理方针执行了 login 办法
loginAfter...
被署理方针执行了 register 办法

能够看到 cglib 动态署理咱们首要运用了 Enhancer 东西类以及完结了 MethodInterceptor 接口

Tips: 假如被署理类方针完结了接口就运用 JDK 动态署理,不然运用 cglib 动态署理

3.5、单例形式

单例形式共有 5 种写法:

1、懒汉式

2、饿汉式

3、两层查看式

4、静态内部类式

5、枚举式

3.5.1、懒汉式

public class LazySingleton {
    private static LazySingleton instance;
    private LazySingleton(){
    }
    public synchronized static LazySingleton getInstance(){
        if(instance == null){
            instance = new LazySingleton();
        }
        return instance;
    }
}

这种办法每次调用 getInstance 办法的时分都会进行同步,形成不必要的同步开支

3.5.2、饿汉式

public class HungrySingleton {
    private static HungrySingleton instance = new HungrySingleton();
    private HungrySingleton(){
    }
    public static HungrySingleton getInstance(){
        return instance;
    }
}

这种办法会在类加载的时分就完结实例的创立,假如从始至终没有运用该实例,则会形成内存的糟蹋

3.5.3、两层查看式

public class DoubleCheckSingleton {
    private volatile static DoubleCheckSingleton instance;
    private DoubleCheckSingleton(){
    }
    public static  DoubleCheckSingleton getInstance(){
        if(instance == null){
            synchronized (DoubleCheckSingleton.class){
                if(instance == null){
                    instance = new DoubleCheckSingleton();
                }
            }
        }
        return instance;
    }
}

这种办法相对来说比较完美一些,可是在 jdk 1.5 之前,高并发的状况下,还是会存在一些问题。如下代码:

instance = new DoubleCheckSingleton();

上述这行代码实践上并不是一个原子操作,它最终会被编译成多条指令,首要做了三件工作:

1、给 instance 实例分配内存

2、调用 DoubleCheckSingleton 构造函数,初始化成员字段

3、将 instance 指向分配的内存(此刻 instance 就不为 null 了)

在 JDK 1.5 之前,高并发的状况下 2,3 的次序是无法确保的,可能为:1-2-3,也可能为:1-3-2。在 JDK 1.5 之后,官方详细化了 volitile 要害字,上述 instance 方针每次都会从主内存读取。当然,volatile 要害字或多或少会影响性能,可是考虑到程序的正确性,这点牺牲也是值得的

优点:资源利用率高,第一次调用 getInstance 办法单例方针才会被实例化,效率高。

缺陷:第一次加载稍慢,在 jdk 1.5 之前可能会失效

3.5.4、静态内部类式

public class StaticInnerClassSingleton {
    private StaticInnerClassSingleton(){
    }
    private static final class Holder{
        private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
    }
    public static StaticInnerClassSingleton getInstance(){
        return Holder.INSTANCE;
    }
}

第一次调用 getInstance 办法时才会去加载 Holder 并初始化 INSTANCE,这样既确保了线程的安全也确保了实例的仅有性

3.5.5、枚举式

public enum EnumSingleton {
    INSTANCE;
}

默许枚举的实例是线程安全的,并且在任何状况下都是单例,可是这种办法可读性不高

3.6、制作者形式

制作者形式首要用来构建方针,将方针的构建与表明进行别离,它更加注重方针的构建进程

public class Computer {
    private final String cpu;
    private final String ram;
    private final String rom;
    private Computer(Builder builder){
        cpu = builder.cpu;
        ram = builder.ram;
        rom = builder.rom;
    }
    public String getCpu() {
        return cpu;
    }
    public String getRam() {
        return ram;
    }
    public String getRom() {
        return rom;
    }
    public static class Builder{
        private  String cpu;
        private  String ram;
        private  String rom;
        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }
        public Builder ram(String ram) {
            this.ram = ram;
            return this;
        }
        public Builder rom(String rom) {
            this.rom = rom;
            return this;
        }
        public Computer build(){
            return new Computer(this);
        }
    }
    public static void main(String[] args) {
        final Computer computer = new Computer.Builder()
                .cpu("英特尔")
                .ram("8G")
                .rom("128G")
                .build();
        System.out.println(computer.getCpu());
        System.out.println(computer.getRam());
        System.out.println(computer.getRom());
    }
}
//打印成果
英特尔
8G
128G

3.7、原型形式

原型形式首要用于构建方针,经过复制原型方针来创立新的方针,复制办法首要分为两种:

1、浅复制

2、深复制

3.7.1、浅复制

复制一个方针时,假如方针里边的是根本类型,则复制的是根本类型的值。假如方针里边是引证类型,则复制的是引证类型的地址,此刻并没有开辟新的内存空间

class Test {
    static class Student implements Cloneable{
        public String name;
        public Student(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    '}';
        }
        @NonNull
        @Override
        protected Student clone()  {
            try {
                return (Student) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    public static void main(String[] args) {
        //浅复制
        ArrayList<Student> stringList = new ArrayList<>();
        Student stu = new Student("erdai");
        stringList.add(stu);
        stringList.add(new Student("erdai666"));
        System.out.println(stringList);
        //浅复制中心代码
        ArrayList<Student> newStringList = (ArrayList<Student>) stringList.clone();
        System.out.println(newStringList);
        //改动 stu 内的值,成果两个调集的值都变了
        stu.name = "erdai777";
        System.out.println(stringList);
        System.out.println(newStringList);
    }
}
//打印成果
[Student{name='erdai'}, Student{name='erdai666'}]
[Student{name='erdai'}, Student{name='erdai666'}]
[Student{name='erdai777'}, Student{name='erdai666'}]
[Student{name='erdai777'}, Student{name='erdai666'}]

3.7.2、深复制

复制一个方针时,假如方针里边的是根本类型,则复制的是根本类型的值,假如方针里边是引证类型,则将引证类型也复制一份,此刻开辟了新的内存空间

class Test {
    static class Student implements Cloneable{
        public String name;
        public Student(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    '}';
        }
        @NonNull
        @Override
        protected Student clone()  {
            try {
                return (Student) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    public static void main(String[] args) {
        //深复制
        ArrayList<Student> stringList = new ArrayList<>();
        Student stu = new Student("erdai");
        stringList.add(stu);
        stringList.add(new Student("erdai666"));
        System.out.println(stringList);
      	//深复制中心代码
        ArrayList<Student> newStringList = new ArrayList<>();
        for (Student student : stringList) {
            newStringList.add(student.clone());
        }
        System.out.println(newStringList);
        //改动 stu 内的值,只有 StringList 的值会变,newStringList 不会变
        stu.name = "erdai777";
        System.out.println(stringList);
        System.out.println(newStringList);
    }
}
//打印成果
[Student{name='erdai'}, Student{name='erdai666'}]
[Student{name='erdai'}, Student{name='erdai666'}]
[Student{name='erdai777'}, Student{name='erdai666'}]
[Student{name='erdai'}, Student{name='erdai666'}]

3.8、适配器形式

适配器形式首要用于适配别的一个不兼容的方针一同工作,首要分 3 种办法:

1、类适配

2、方针适配

3、接口适配

3.8.1、类适配

//1、界说一个需求被适配的类
class Adaptee{
    public void adaptee(){
        System.out.println("调用了被适配的办法");
    }
}
//2、界说一个方针接口
interface Target{
    void request();
}
//现在咱们需求在方针接口的 request 办法中调用 Adaptee 的 adaptee 办法,如何完结呢?
//3、界说一个适配器的类
class Adapter extends Adaptee implements Target{
    @Override
    public void request(){
        System.out.println("经过适配器,衔接方针办法");
        super.adaptee();
    }
}
//4、测验
public class ClassClient {
    public static void main(String[] args){
        Target target = new Adapter();
        target.request();
    }
}
//打印成果
经过适配器,衔接方针办法
调用了被适配的办法

3.8.2、方针适配

电源适配器:将 200V 的电话转换为 5V 输出

//1、界说一个电压的接口
interface AC{
    int outputAC();
}
//2、界说一个 220V 的完结类
class AC220 implements AC{
    @Override
    public int outputAC(){
        return 220;
    }
}
//3、适配器接口,outputDC5V 办法用于将输入的电压变为 5V 后输出
interface DC5Adapter{
    int outputDC5V(AC ac);
}
//4、完结电源适配器
class PowerAdapter implements DC5Adapter{
    @Override
    public int outputDC5V(AC ac){
        int outputAC = ac.outputAC();
        //变压器
        int adapterOutput = outputAC / 44;
        System.out.println("收到:" + outputAC + "V的电压,经过适配器转换,输出为:" + adapterOutput + "V");
        return adapterOutput;
    }
}
//5、测验
public class ObjectClient {
    public static void main(String[] args) {
        DC5Adapter adapter = new PowerAdapter();
        AC ac = new AC220();
        adapter.outputDC5V(ac);
    }
}
//打印成果
收到:220V的电压,经过适配器转换,输出为:5V

3.8.3、接口适配

在实践开发中,经常会遇到接口中界说了太多的办法,而有些办法咱们是用不到的,此刻咱们就能够经过适配器形式适配接口

//1、界说一个接口,里边有两个笼统办法
interface ITest{
  void test();
  void test1();
}
//2、界说一个适配器的笼统类
abstract class AdapterWrapper implements ITest{
    @Override
    public void test() {
    }
    @Override
    public void test1() {
    }
}
//3、接下来,咱们就能够继承适配器的笼统类,然后去挑选需求完结的办法
class Test extends AdapterWrapper{
   @Override
    public void test() {
        System.out.println("erdai666");
    }
}
//4、测验
public class InterfaceClient {
    public static void main(String[] args) {
        Test test = new Test();
        test.test();
    }
}
//打印成果
erdai666

3.9、装修者形式

装修者形式首要用于装修一个类,到达功用增强的意图

如下比如:我想吃个蛋炒饭,可是独自一个蛋炒饭我觉得不好吃,我想在上面加火腿,加牛肉。咱们运用装修者形式来完结它

//1、界说一个炒饭的接口
interface Rice {
    fun cook()
}
//2、界说一个炒饭接口的完结类:蛋炒饭
class EggFriedRice: Rice {
    override fun cook() {
        println("蛋炒饭")
    }
}
//3、界说一个炒饭的笼统装修类
abstract class RiceDecorate(var rice: Rice): Rice
//4、往蛋炒饭中加火腿
class HamFriedRiceDecorate(rice: Rice): RiceDecorate(rice) {
    override fun cook() {
        rice.cook()
        println("加火腿")
    }
}
//5、往蛋炒饭中加牛肉
class BeefFriedRiceDecorate(rice: Rice): RiceDecorate(rice) {
    override fun cook() {
        rice.cook()
        println("加牛肉")
    }
}
//6、测验
fun main(){
    //蛋炒饭
    val rice = EggFriedRice()
    //加火腿
    val hamFriedRiceDecorate = HamFriedRiceDecorate(rice)
    //加牛肉
    val beefFriedRiceDecorate = BeefFriedRiceDecorate(hamFriedRiceDecorate)
    beefFriedRiceDecorate.cook()
}
//打印成果
蛋炒饭
加火腿
加牛肉

3.10、外观形式

外观形式首要用于简化体系的运用,它对外提供一个高层接口,并将子体系的功用进行封装

//1、提供一些子体系的类
class CPU{
    public void startup(){
        System.out.println("cpu startup");
    }
    public void shutdowm(){
        System.out.println("cpu shutdowm");
    }
}
class RAM{
    public void startup(){
        System.out.println("ram startup");
    }
    public void shutdowm(){
        System.out.println("ram shutdowm");
    }
}
class ROM{
    public void startup(){
        System.out.println("rom startup");
    }
    public void shutdowm(){
        System.out.println("rom shutdowm");
    }
}
//2、外观类
class Computer{
    private CPU cpu;
    private RAM ram;
    private ROM rom;
    public Computer(){
        cpu = new CPU();
        ram = new RAM();
        rom = new ROM();
    }
    public void startup(){
        cpu.startup();
        ram.startup();
        rom.startup();
    }
    public void shutdowm(){
        cpu.shutdowm();
        ram.shutdowm();
        rom.shutdowm();
    }
}
//3、测验
public class FacadeClient {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.startup();
        computer.shutdowm();
    }
}
//打印成果
cpu startup
ram startup
rom startup
cpu shutdowm
ram shutdowm
rom shutdowm

外观形式优点:

1、将对子体系的依靠转换为对外观类的依靠

2、对外部隐藏子体系的详细完结

3、增强了安全性

3.11、桥接形式

桥接形式首要用于笼统与完结之间的桥接,完结二者的解耦

比如:画圆形和长方形,并给他们涂上不同的色彩

//1、创立画色彩的接口:桥接接口
interface DrawAPI{
    void drawColor();
}
//2、创立完结类
class RedDraw implements DrawAPI{
    @Override
    public void drawColor(){
        System.out.println("red color");
    }
}
class GreenDraw implements DrawAPI{
    @Override
    public void drawColor(){
        System.out.print("green color");
    }
}
//3、界说一个笼统类 Shape(形状):持有 DrawAPI 的 引证
abstract class Shape{
    protected DrawAPI drawAPI;
    public Shape(DrawAPI drawAPI){
        this.drawAPI = drawAPI;
    }
    public abstract void draw();
}
//4、完结类,画详细的形状,并增加色彩
class Circle extends Shape{
    public Circle(DrawAPI drawAPI) {
        super(drawAPI);
    }
    @Override
    public void draw() {
        System.out.print("draw Circle with ");
        drawAPI.drawColor();
    }
}
class Rectangle extends Shape{
    public Rectangle(DrawAPI drawAPI) {
        super(drawAPI);
    }
    @Override
    public void draw() {
        System.out.print("draw Rectangle with ");
        drawAPI.drawColor();
    }
}
//测验
public class BridgeClient {
    public static void main(String[] args) {
        Shape redCircle = new Circle(new RedDraw());
        Shape greenRectangle = new Rectangle(new GreenDraw());
        redCircle.draw();
        greenRectangle.draw();
    }
}
//打印成果
draw Circle with red color
draw Rectangle with green color

桥接形式优点:

1、把事物和其详细完结分开,使得他们各自能够独立的改变

2、桥接接口作为你一个维度,笼统类作为一个维度,两则能够随意组合

3.12、组合形式

组合形式的特点便是把一组类似的方针,当作一个单一的方针

//1、界说一个笼统类
abstract class Component{
    public abstract void operation();
    public void add(Component component){
    }
    public void remove(Component component){
    }
}
//2、界说一组类似的完结类
class ComponentImpl1 extends Component{
    @Override
    public void operation() {
        System.out.println("ComponentImpl1 operation");
    }
}
class ComponentImpl2 extends Component{
    @Override
    public void operation() {
        System.out.println("ComponentImpl2 operation");
    }
}
//3、界说一个组合类
class Combine extends Component{
    private final List<Component> list = new ArrayList<>();
    @Override
    public void operation() {
        for (Component component : list) {
            component.operation();
        }
    }
    @Override
    public void add(Component component) {
        list.add(component);
    }
    @Override
    public void remove(Component component) {
        list.remove(component);
    }
}
//4、测验
public class CombineClient {
    public static void main(String[] args) {
        Component c1 = new ComponentImpl1();
        Component c2 = new ComponentImpl2();
        Component combine = new Combine();
        combine.add(c1);
        combine.add(c2);
        combine.operation();
        combine.remove(c2);
        combine.operation();
    }
}
//打印成果
ComponentImpl1 operation
ComponentImpl2 operation
ComponentImpl1 operation

3.13、观察者形式

观察者形式首要用于当一个方针改动,其他方针能收到这种改变

//1、界说一个观察者的接口
interface Observer {
    fun onChange(o: Any?)
}
//2、界说一个被观察者的接口
interface Observable {
    fun addObserver(observer: Observer?)
    fun removeObserver(observer: Observer?)
    fun changeEvent(o: Any?)
}
//3、界说一个被观察者的完结类
class ObservableImpl : Observable {
    private val observers: MutableList<Observer>
    init {
        observers = LinkedList()
    }
    override fun addObserver(observer: Observer?) {
        if (observer == null) return
        if (observers.contains(observer)) return
        observers.add(observer)
    }
    override fun removeObserver(observer: Observer?) {
        if (observer == null) return
        if (observers.contains(observer)) {
            observers.remove(observer)
        }
    }
    override fun changeEvent(o: Any?) {
        for (observer in observers) {
            observer.onChange(o)
        }
    }
}
//4、界说一个观察者的完结类
class ObserverImpl : Observer {
    override fun onChange(o: Any?) {
        println("${javaClass.simpleName}: $o")
    }
}
//5、测验
fun main() {
    val observable: Observable = ObservableImpl()
    val observer1: Observer = ObserverImpl()
    val observer2: Observer = ObserverImpl()
    val observer3: Observer = ObserverImpl()
    observable.addObserver(observer1)
    observable.addObserver(observer2)
    observable.addObserver(observer3)
    observable.changeEvent("erdai666")
}
//6、打印成果
ObserverImpl: erdai666
ObserverImpl: erdai666
ObserverImpl: erdai666

3.14、模版办法形式

模版办法形式界说了一套算法框架,将一些过程交由详细的字类去完结

模版办法形式首要有以下人物:

1、笼统类:界说了一套算法框架

2、详细完结类

//1、笼统类:界说了一套算法框架
abstract class Game{
    abstract void init();
    abstract void startPlay();
    abstract void endPlay();
    //模版办法
    public final void play(){
        //初始化游戏
        init();
        //开端游戏
        startPlay();
        //完毕游戏
        endPlay();
    }
}
//2、界说完结类
class LOL extends Game{
    @Override
    void init() {
        System.out.println("LOL initialized!start play...");
    }
    @Override
    void startPlay() {
        System.out.println("LOL started,enjoy it...");
    }
    @Override
    void endPlay() {
        System.out.println("LOL finished...");
    }
}
//3、测验
public class TemplateClient {
    public static void main(String[] args) {
        Game game = new LOL();
        game.play();
    }
}
//打印成果
LOL initialized!start play...
LOL started,enjoy it...
LOL finished...

3.15、责任链形式

//1、界说一个责任链的笼统类
abstract class AbstractLogger{
    public static int INFO = 1;
    public static int DEBUG = 2;
    public static int ERROR = 3;
    protected int level;
    //责任链的下一个元素
    protected AbstractLogger nextLogger;
    public void setNextLogger(AbstractLogger nextLogger){
        this.nextLogger = nextLogger;
    }
    public void logMessage(int level,String message){
        if(this.level <= level){
            write(message);
        }
        if(nextLogger != null){
            nextLogger.logMessage(level,message);
        }
    }
    abstract protected void write(String message);
}
//2、创立完结类
class ConsoleLogger extends AbstractLogger{
    public ConsoleLogger(int level){
        this.level = level;
    }
    @Override
    protected void write(String message) {
        System.out.println("Standard Console::Logger:" + message);
    }
}
class ErrorLogger extends AbstractLogger{
    public ErrorLogger(int level){
        this.level = level;
    }
    @Override
    protected void write(String message) {
        System.out.println("Error::Logger:" + message);
    }
}
class FileLogger extends AbstractLogger{
    public FileLogger(int level){
        this.level = level;
    }
    @Override
    protected void write(String message) {
        System.out.println("File::Logger:" + message);
    }
}
//测验
public class ChainClient {
    private static AbstractLogger getChain(){
        AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
        AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
        AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
        errorLogger.setNextLogger(fileLogger);
        fileLogger.setNextLogger(consoleLogger);
        return errorLogger;
    }
    public static void main(String[] args) {
        AbstractLogger chain = getChain();
        chain.logMessage(AbstractLogger.INFO,"This is an information.");
        chain.logMessage(AbstractLogger.DEBUG,"This is a debug level information.");
        chain.logMessage(AbstractLogger.ERROR,"This is an error information.");
    }
}
//打印成果
Standard Console::Logger:This is an information.
File::Logger:This is a debug level information.
Standard Console::Logger:This is a debug level information.
Error::Logger:This is an error information.
File::Logger:This is an error information.
Standard Console::Logger:This is an error information.

3.16、解说器形式

解说器形式便是界说一个解说器的规矩去解说方针

//1、创立一个解说器的接口
interface Expression{
    boolean interpret(String context);
}
//2、创立完结类
class TerminalExpression implements Expression{
    private final String data;
    public TerminalExpression(String data) {
        this.data = data;
    }
    @Override
    public boolean interpret(String context) {
        return context.contains(data);
    }
}
class OrExpression implements Expression{
    private Expression expression1;
    private Expression expression2;
    public OrExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }
    @Override
    public boolean interpret(String context) {
        return expression1.interpret(context) || expression2.interpret(context);
    }
}
class AndExpression implements Expression{
    private Expression expression1;
    private Expression expression2;
    public AndExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }
    @Override
    public boolean interpret(String context) {
        return expression1.interpret(context) && expression2.interpret(context);
    }
}
//3、规矩,测验
public class InterpretClient {
    //规矩:小明和二代都是男的
    public static Expression getMaleExpression(){
        Expression xiaoming = new TerminalExpression("小明");
        Expression erdai = new TerminalExpression("二代");
        return new OrExpression(xiaoming, erdai);
    }
    //规矩:小红是已婚的
    public static Expression getMarriedWomenExpression(){
        Expression xiaohong = new TerminalExpression("小红");
        Expression married = new TerminalExpression("已婚");
        return new AndExpression(xiaohong, married);
    }
    public static void main(String[] args) {
        Expression isMale = getMaleExpression();
        Expression isMarriedWomen = getMarriedWomenExpression();
        System.out.println("二代是男的?:" + isMale.interpret("二代"));
        System.out.println("小红是否现已成婚了?:" + isMarriedWomen.interpret("小红已婚"));
    }
}
//打印成果
二代是男的?:true
小红是否现已成婚了?:true

3.17、中介者形式

中介者形式首要是经过提供一个中介类来下降多个方针之间的通信复杂度

//1、创立一个一致行为的接口
interface Mediator{
    void showMessage(String message);
}
//2、创立完结类
class User implements Mediator{
    @Override
    public void showMessage(String message){
        System.out.println("User:" + message);
    }
}
//3、创立中介类
class ChatRoom implements Mediator{
    @Override
    public void showMessage(String message) {
        (new User()).showMessage(message);
    }
}
//4、测验
public class MediatorClient {
    public static void main(String[] args) {
        Mediator room = new ChatRoom();
        room.showMessage("Hi,erdai");
    }
}
//打印成果
User:Hi,erdai

3.18、迭代器形式

迭代器形式首要用于次序访问调集方针的元素,而不需求知道其底层表明

//1、创立接口
interface Iterator{
    boolean hasNext();
    Object next();
}
interface Container{
    Iterator getIterator();
}
//2、创立完结类
class NameRepository implements Container{
    String[] names = {"小明","小红","二代"};
    @Override
    public Iterator getIterator() {
        return new NameIterator();
    }
    private class NameIterator implements Iterator{
        int index;
        @Override
        public boolean hasNext() {
            return index < names.length;
        }
        @Override
        public Object next() {
            if(hasNext()){
                return names[index++];
            }
            return null;
        }
    }
}
//3、测验
public class IteratorClient {
    public static void main(String[] args) {
        NameRepository nameRepository = new NameRepository();
        final Iterator iterator = nameRepository.getIterator();
        while (iterator.hasNext()){
            String name = (String) iterator.next();
            System.out.println(name);
        }
    }
}
//打印成果
小明
小红
二代

3.19、享元形式

享元形式首要用于削减创立方针的数量,削减内存占用,进步性能

//1、创立一个学生类
class Student {
    private String name;
    private int age;
    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;
    }
}
//2、享元工厂类
class StudentFactory {
    private static final Map<Object,Object> stuMap = new HashMap<>();
    public static Student getStudent(String key){
        if(stuMap.containsKey(key)){
            return (Student) stuMap.get(key);
        }else{
            Student stu = new Student();
            stuMap.put(key, stu);
            return stu;
        }
    }
}
//3、测验
public class EnjoyClient {
    private static final String[] keys = new String[]{"二代","小明","小红","张三","李四","二代","小红"};
    public static void main(String[] args) {
        for (String key : keys) {
            final Student student = StudentFactory.getStudent(key);
            student.setName(key);
            System.out.println(student.getName() + " HashCode:"+ student.hashCode());
        }
    }
}
//打印成果
二代 HashCode:93122545
小明 HashCode:2083562754
小红 HashCode:1239731077
张三 HashCode:557041912
李四 HashCode:1134712904
二代 HashCode:93122545
小红 HashCode:1239731077

3.20、访问者形式

访问者形式首要便是经过访问者类去访问方针元素并进行相关操作

//1、创立待访问的元素方针接口
interface Subject{
    void accept(Visitor visitor);
    String getSubject();
}
//2、创立访问者接口
interface Visitor{
    void visit(Subject sub);
}
//3、创立各自的完结类
class MySubject implements Subject{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    @Override
    public String getSubject() {
        return "love";
    }
}
class MyVisitor implements Visitor{
    @Override
    public void visit(Subject sub) {
        System.out.println("visit the subject:" + sub.getSubject());
    }
}
//4、测验
public class VisitorClient {
    public static void main(String[] args) {
        Subject subject = new MySubject();
        Visitor visitor = new MyVisitor();
        subject.accept(visitor);
    }
}
//打印成果
visit the subject:love

3.21、指令形式

指令形式用于给不同的方针下达不同的指令

//1、创立一个指令接口
interface Order{
    void execute();
}
//2、创立一个恳求类
class Stock{
    private String name = "ABC";
    private int quantity = 10;
    public void buy(){
        System.out.println("buy,name:" + name + " quantity:" + quantity);
    }
    public void sell(){
        System.out.println("sell,name:" + name + " quantity:" + quantity);
    }
}
//3、常见指令的完结类,完结不同的指令
class BuyStock implements Order{
    private final Stock stock;
    public BuyStock(Stock stock) {
        this.stock = stock;
    }
    @Override
    public void execute() {
        stock.buy();
    }
}
class SellStock implements Order{
    private final Stock stock;
    public SellStock(Stock stock) {
        this.stock = stock;
    }
    @Override
    public void execute() {
        stock.sell();
    }
}
//4、创立指令的调用类
class Broker{
    private List<Order> orderList = new ArrayList<>();
    public void takeOrder(Order order){
        orderList.add(order);
    }
    public void placeOrders(){
        for (Order order : orderList) {
            order.execute();
        }
    }
}
//5、测验
public class OrderClient {
    public static void main(String[] args) {
        Stock stock = new Stock();
        BuyStock buyStock = new BuyStock(stock);
        SellStock sellStock = new SellStock(stock);
        Broker broker = new Broker();
        broker.takeOrder(buyStock);
        broker.takeOrder(sellStock);
        broker.placeOrders();
    }
}
//打印成果
buy,name:ABC quantity:10
sell,name:ABC quantity:10

3.22、备忘录形式

备忘录形式首要用于保存方针的某个状况,以便在恰当的时分康复方针

//1、创立一个备忘录类
class Memento{
    public String value;
    public Memento(String value) {
        this.value = value;
    }
}
//2、创立一个原始类
class Original{
    public String value;
    public Original(String value) {
        this.value = value;
    }
    public Memento createMemento(){
        return new Memento(value);
    }
    public void restoreMemento(Memento memento){
        this.value = memento.value;
    }
}
//3、创立一个存储备忘录的类
class Storage{
    public Memento memento;
    public Storage(Memento memento) {
        this.memento = memento;
    }
}
//4、测验
public class MementoClient {
    public static void main(String[] args) {
        //创立原始类
        Original original = new Original("erdai666");
        //创立一个存储类存储备忘录
        Storage storage = new Storage(original.createMemento());
        //修正原始类的状况
        original.value = "erdai";
        //回复原初始类的状况
        original.restoreMemento(storage.memento);
        System.out.println(original.value);
    }
}
//打印成果
erdai666

四、总结

本篇文章咱们介绍了:

1、Java 六大规划准则,并都进行了举例阐明:

1、开闭准则

2、里氏替换准则

3、依靠倒置准则

4、迪米特规律

5、接口阻隔准则

6、单一指责准则

其中,开闭准则是最根底的准则,其他准则都是开闭准则的详细形状

2、24 种规划形式,并进行了举例阐明

好了,本篇文章到这里就完毕了,希望能给你带来协助

感谢你阅读这篇文章

你的点赞,谈论,是对我巨大的鼓励!

欢迎关注我的公众号: sweetying ,文章更新可第一时间收到

假如有问题,公众号内有加我微信的进口,在技能学习、个人成长的道路上,咱们一同前进!