周日. 6 月 22nd, 2025

OOP是一种非常方便的范式,可以帮助你识别需求,同时也使它们更容易理解。不同的OOP概念,如继承和多态,在流行的应用程序中有许多用例。然而,在某些情况下,单纯的OOP是不够的。为了实现一个特定的功能,你可能需要以一种使你的代码更好、更易懂的方式使用OOP概念。在这篇文章中,你将学习五种设计模式,它们可以让你作为Java程序员的生活更美好。在此之前,让我们先搞清楚两件事。为什么要用设计模式?假设你有一个类Boat,它有不同的子类代表不同类型的船。一个Boat对象可以执行两个动作,摇摆和滚动。abstractclassBoat{voidsway(){…}voidroll(){…}abstractvoidpresent();}sway()和roll()方法被每个子类继承,因为它们对每种类型的船都是相同的。present()方法是抽象的,因为每种船都有自己特定的展示方式。classFishBoatextendsBoat{voidpresent(){…}}void DinghyBoat extends Boat {voidpresent(){…}}这两艘船,FishBoat和DinghyBoat继承了Boat类。到目前为止,一切都运行得很好。你也可以根据需要添加新的船。现在,有一个新的功能需求,你需要给一种新的船,SubBoat添加一个潜水功能。有了这个功能,船就变成了潜水艇,并且可以潜入水下。问题是,你在哪里定义dive()方法?有两种可能的解决方案。继承这是一个很明显的方法。你可以在Boat类中定义dive()方法,然后由SubBoat继承。这样可以确保代码复用和代码可维护性。这个解决方案有什么问题呢?好吧,你在超类中添加了dive()方法,这意味着所有的子类都继承了这个功能。但是,我们不想看到渔船变成潜水艇并潜水。关键是,并不是所有的类都需要继承你的新功能,也不应该这样。接口继承解决方案没有达到我们的目的,所以你可以尝试创建一个Diveable接口,它定义了dive()方法。只有那些应该具有潜水功能的船只才会实现这个接口,并重写dive()方法。这解决了前一个解决方案的问题。只有必要的类才会继承dive()方法。但是这也带来了一系列新的问题。由于你使用了一个接口,你没有实际实现方法。所以,你需要在子类中实现方法。这看起来一开始并不糟糕,但不要被骗了。如果你还有50多个类想要新功能呢?你就得实现同一个方法50次。这是一个噩梦,因为它工作量太大,并且完全破坏了代码可维护性。从上面的例子中,你已经明白了使用OOP原则以传统方式并不能有效地解决问题。我们需要一种新的解决方式来解决这个和许多其他问题。这就是设计模式发挥作用的地方。什么是设计模式?当传统方法不起作用时,你就知道是时候制定新的解决方案了。这就是软件开发所涉及到的内容,改变你当前无效的方式,提出更有效的方法。让我们看看我们遇到的问题。在继承中,你添加了一个新功能,但在此过程中,你也改变了现有功能。本来不应该潜水的船突然发现自己继承了dive()方法。使用接口似乎解决了问题,但它引入了新问题。对于每个需要新功能的类,你都必须实现dive()方法。如果功能有一点变化,你就需要在所有实现该方法的类中进行修改。根据设计原则,在你有一些代码是新需求时,行为需要被封装并与现有代码分开,以免导致意外后果。这个原则是许多设计模式的基础,其中一些你将在本文中看到。你还将看到用于解决上述问题的设计模式。1.单例模式在这种模式下,你只能创建一个类的实例。即使你创建多个引用变量,它们也都指向同一个对象。很简单吧?但是如何做到这一点呢?如何确保只创建一个对象呢?你会通过一个例子来理解。假设我们有一个类Probe,它有自己的实例变量和方法。classProbe{// Instance variables// Important methods}我们的类Probe不喜欢有多个对象。所以我们把它的构造函数设为私有。privateProbe(){// Initialize variables here}现在,这个构造函数只能从类内部调用。创建一个静态方法getInstance()这个方法接收Probe类的引用变量,并检查对象是否已经被实例化。如果没有,那么就创建一个新对象并返回给客户端。privatestatic Probe getInstance(Probe probe){if(probe == null) probe = new Probe();return probe;}由于getInstance()是一个静态方法,它只能在类级别而不是对象级别调用.。每次调用这个方法时,它都返回相同的对象.因此,这种模式能够阻止你创建多个对象。单例模式用于只需要一个实例的对象.例如,注册设置和日志对象只需要一个实例,否则可能会导致意外副作用。2.观察者模式假设你关注了一个社交媒体页面。每当这个页面添加一条新帖子时,你希望收到通知。所以,在一个对象(页面)执行一个动作(添加帖子)时,另一个对象(关注者)被通知.这种情况可以通过观察者模式来实现让我们创建一个类Page和一个接口Follower。页面可以有不同类型的关注者,例如普通用户,招聘者和官方人员。我们将为每种关注者类型创建一个类,并且所有这些类都将实现Follower接口在这里, Page类是主题(subject),而关注者是观察者(observer)类。观察者模式定义了主题和观察者之间的一对多关系.如果主题改变了状态(页面添加了新帖子),所有观察者即关注者都会收到通知。Page类将具有以下方法:registerFollower():此方法注册新的关注者。notifyFollowers():此方法通知所有关注者该页面有新帖子。getLatestPost()和 addNewPost():获取和设置页面上的最新帖子。另一方面,Follower接口只有一个方法update(),它将被实现这个接口的关注者类型重写,也称为具体观察者。interfaceFollower{publicvoidupdate();}update()方法在主题需要通知观察者状态变化时被调用,即有新帖子。让我们实现Page类,即主题。classPage{private ArrayList followers; String latestPost;publicPage(){ followers = new ArrayList();}publicvoidregisterFollower(Follower f){ followers.add(f);}publicvoidnotifyFollowers(){for(int i =; i < followers.size(); i++){ Follower follower = followers.get(i); follower.update();} }public String getLatestPost(){return latestPost;}publicvoidaddNewPost(String post){this.latestPost = post; notifyFollowers();}}在这个类中,我们有一个关注者列表。当一个新的关注者想要关注页面时,它调用registerFollower()方法。latestPost保存了页面添加的新帖子。当添加一个新帖子时,调用notifyFollowers()方法,它遍历每个关注者,并通过调用update()方法通知他们。现在,让我们实现我们的第一种关注者,UserclassUserimplementsFollower{ Page page;publicUser(Page page){this.page = page; page.registerFollower(this);}publicvoidupdate(){ System.out.println(“普通用户看到的最新帖子:”+ page.getLatestPost());}}当创建一个新的User对象时,它接收它想要关注的页面,并注册。当页面添加一条新帖子时,User通过update()方法得到通知,User可以以自己的方式实现这个方法。让我们再有两个类想要关注页面。classRecruiterimplementsFollower{ String company;//其余与User类相同}classOfficialimplementsFollower{ String designation;//其余与User类相同}让我们在主类中测试这个模式。首先,创建一个页面并添加一条新帖子。Page page = new Page();page.addNewPost(“I am feeling lucky!”);还没有人关注这个页面,所以这不会通知任何人。现在,一个普通用户关注了这个页面,它又添加了另一条帖子。User user = new User(page);page.addNewPost(“Its a beautiful day!”);现在,用户会收到通知,并给出以下输出。普通用户看到的最新帖子: Its a beautiful day!接下来,招聘者和官方人员也关注了这个帖子。Recruiter recruiter = new Recruiter(page);Official official = new Official(page);page.addNewPost(“Ready to go for a run!!”);他们三个都会收到这个活动的通知。普通用户看到的最新帖子: Ready to go for a run!!招聘者看到的最新帖子: Ready to go for a run!!官方人员看到的最新帖子: Ready to go for a run!!3.策略模式现在,让我们回到船的问题。我们想给一些船添加潜水功能。两种方法,继承和方法重写都没有达到我们的目的。如果你回忆一下设计原则,我们需要将变化的代码与已经存在的代码分开。唯一变化的部分是dive()行为,所以我们创建一个接口Diveable,并创建两个更多的类来实现它。interfaceDiveable{publicvoiddive();}classDiveBehaviourimplementsDiveable{publicvoiddive(){// Implementation here }}classNoDiveBehaviourimplementsDiveable{publicvoiddive(){// Implementation here }}现在,在你的Boat类中,创建一个接口的引用变量,并有一个方法performDive()来调用这个dive()方法。abstractclassBoat{ Diveable diveable;voidsway(){…}voidroll(){…}abstractvoidpresent();publicvoidperformDive(){ diveable.dive();}}FishBoat和DinghyBoat类不应该有潜水行为,所以它们将继承NoDiveBehaviour类。让我们看看如何做到这一点。classFishBoatextendsBoat{…publicFishBoat(){ diveable = new NoDiveBehaviour();} …}当引用变量diveable被实例化为NoDiveBehaviour对象时,FishBoat类继承了这个类的dive()方法。对于新类SubBoat,可以继承一个新行为classSubBoatextendsBoat{… publicFishBoat(){ diveable = new DiveBehaviour();} …}现在,让我们测试一下功能。Boat fishBoat = new FishBoat();fishBoat.performDive();当调用performDive()时,它调用NoDiveBehaviour类的dive方法Boat subBoat = new SubBoat();subBoat.performDive();这执行了一个完全不同的动作,因为它调用了实际的潜水行为。因此,我们的新船变成了潜水艇并潜水4.装饰器模式有时候,你想对你的功能做一些修改.在做这些修改时,你需要确保不改变现有功能.我们以一个类Car为例,它被两个类Ford和Audi扩展。它有一个build()方法以及其他重要方法。这个方法是抽象的,因为每种车都有自己的实现abstractclassCar{abstractvoidbuild();}classFordextendsCar{publicvoidbuild(){ System.out.println(“Ford built”);}}classAudiextendsCar{publicvoidbuild(){ System.out.println(“Audi built”);}}一切都运行得很好。然而,客户想要做一些修改,比如添加彩色大灯,添加尾翼或添加氮气。你将如何做这些添加呢?一种方法是为每种修改创建不同的子类,如AudiWithSpoiler, FordWithNitrous等等。但是你可以看到这很快就成为一个大问题.可能组合没有限制另一种方法是将每种修改作为一个实例变量,并在需要修改的地方调用build()方法。然而,每有一个新修改,你就需要修改现有代码,从而增加了引入错误的可能性有一种更好、更灵活的方式来做这件事。你可以为每种修改定义单独的类,并将你的车包装在那个对象中。这是什么意思呢?你马上就会明白创建一个类CarModifications继承Car。我将把这个类称为mod类abstractclassCarModificationsextendsCar{ Car car;publicCarModifications(Car car){this.car = car;}}通过在CarModifications中创建一个Car对象,你将Car包装在mod类中。mod类是一个抽象类,并被三个更多的类扩展: ColorLight, Spoiler和Nitrous。classSpoilerextendsCarModifications{publicSpoiler(Car car){super(car);}publicvoidbuild(){ car.build(); addSpoiler();}voidaddSpoiler(){ System.out.println(“Spoiler built”);}}这是一个具体的mod类包装Car.它通过先建造车然后添加尾翼来实现build()方法。其他两个mod类有着相似的实现.现在,让我们测试这个模式。我们将创建一个Audi,并给它添加一个尾翼。Car audi = new Audi();Car audiWithSpoiler = new Spoiler(audi);audiWithSpoiler.build();在你创建一个Car对象后,你使用相同的实例来创建一个新的Car对象,并添加一个尾翼。调用build()方法来执行这个模式,得到以下输出。Audi builtSpoiler built如果你想要一辆带有氮气的车,就再创建一个Car对象。Car audiWithMods = new Nitrous(audiWithSpoiler);audiWithMods.build();输出:Audi builtSpoiler builtNitrous built5.工厂模式这种模式建议用一种不同的方式实例化对象,以提供更多的灵活性来应对变化的需求。当你扩展一个抽象类并实现它的抽象方法时,你创建了一个具体类。随着新需求的出现,你的代码中的具体类的数量可能会增加。这使得你很难修改你的代码。所以,遵循相同的原则,变化的行为应该与已经存在的行为分开,工厂模式就是这样实现的。这篇文章已经很长了,所以我将在以后的文章中讨论这种模式。结论用传统方法编写一些场景可能会有问题。重要的是要不断尝试不同的方法,并且愿意改变你解决问题的方式。在这篇文章中,我从介绍我们为什么需要设计模式和它们遵循的原则开始,然后解释了四种设计模式,并给出了例子和代码块。希望这能让你更好地理解它们。

Avatar photo

作者 UU 13723417500

友情提示:现在网络诈骗很多,做跨境电商小心被骗。此号发布内容皆为转载自其它媒体或企业宣传文章,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。---无意冒犯,如有侵权请联系13723417500删除!

声明本文由该作者发布,如有侵权请联系删除。内容不代表本平台立场!

发表回复

服务平台
跨境人脉通
选品平台
U选Market
展会&沙龙
群通天下