我在阅读关于SOLID和其他设计原则的内容。我以为ISP与“面向接口编程而不是实现”是相同的。但看起来这些是不同的原则?
它们之间有什么区别吗?
我在阅读关于SOLID和其他设计原则的内容。我以为ISP与“面向接口编程而不是实现”是相同的。但看起来这些是不同的原则?
它们之间有什么区别吗?
class A {
method1()
method2()
// more methods
method10()
}
class B {
A a = new A()
}
将会变成
interface C {
method1()
method2()
}
class A implements C{
method1()
method2()
// more methods
method10()
}
class B {
C c = new A()
}
这样可以防止B获得比它所知道的更多信息。
ISP关注的是每个接口代表一个独立、连贯的行为的想法。
也就是说,一个对象应该完成的每个逻辑组都应该映射到一个具体的接口。一个类可能希望做很多事情,但每件事情都应该映射到代表该行为的特定接口上。这个想法是每个接口非常专注。
interface Shape{
public int getLength();
public int getWidth();
public int getRadius();
public double getArea();
}
class Rectangle implements Shape{
int length;
int width;
public Rectangle(int length, int width){
this.length = length;
this.width = width;
}
public int getLength(){
return length;
}
public int getWidth(){
return width;
}
public int getRadius(){
// Not applicable
return 0;
}
public double getArea(){
return width * length;
}
}
class Square implements Shape{
int length;
public Square(int length){
this.length = length;
}
public int getLength(){
return length;
}
public int getWidth(){
// Not applicable
return 0;
}
public int getRadius(){
// Not applicable
return 0;
}
public double getArea(){
return length * length;
}
}
class Circle implements Shape{
int radius;
public Circle(int radius){
this.radius = radius;
}
public int getLength(){
// Not applicable
return 0;
}
public int getWidth(){
// Not applicable
return 0;
}
public int getRadius(){
return radius;
}
public double getArea(){
return 3.14* radius * radius;
}
}
public class InterfaceNoSeggration{
public static void main(String args[]){
Rectangle r = new Rectangle(10,20);
Square s = new Square(15);
Circle c = new Circle(2);
System.out.println("Rectangle area:"+r.getArea());
System.out.println("Square area:"+s.getArea());
System.out.println("Circle area:"+c.getArea());
}
}
输出:
java InterfaceNoSeggration
Rectangle area:200.0
Square area:225.0
Circle area:12.56
备注:
Shape
是一个通用的接口,包含了所有 Shape
实现所需的方法,例如 Rectangle
、Circle
和 Square
。但是,只有在相应的 Shape 子类中需要一些方法。
Rectangle : getLength(), getWidth(), getArea()
Square : getLength() 和 getArea()
Circle : getRadius() 和 getArea()
如果没有分离,所有形状都会实现整个 fat 接口:Shape。
interface Length{
public int getLength();
}
interface Width{
public int getWidth();
}
interface Radius{
public int getRadius();
}
interface Area {
public double getArea();
}
class Rectangle implements Length,Width,Area{
int length;
int width;
public Rectangle(int length, int width){
this.length = length;
this.width = width;
}
public int getLength(){
return length;
}
public int getWidth(){
return width;
}
public double getArea(){
return width * length;
}
}
class Square implements Length,Area{
int length;
public Square(int length){
this.length = length;
}
public int getLength(){
return length;
}
public double getArea(){
return length * length;
}
}
class Circle implements Radius,Area{
int radius;
public Circle(int radius){
this.radius = radius;
}
public int getRadius(){
return radius;
}
public double getArea(){
return 3.14* radius * radius;
}
}
public class InterfaceSeggration{
public static void main(String args[]){
Rectangle r = new Rectangle(10,20);
Square s = new Square(15);
Circle c = new Circle(2);
System.out.println("Rectangle area:"+r.getArea());
System.out.println("Square area:"+s.getArea());
System.out.println("Circle area:"+c.getArea());
}
}
注释:
现在,像矩形
、正方形
和圆形
这样的单个形状只实现了必要的接口,并且摆脱了未使用的方法。
IWorker Interface:
public interface IWorker {
public void work();
public void eat();
}
Developer Class :
public class Developer implements IWorker {
@Override
public void work() {
// TODO Auto-generated method stub
System.out.println("Developer working");
}
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("developer eating");
}
}
Robot Class:
public class Robot implements IWorker {
@Override
public void work() {
// TODO Auto-generated method stub
System.out.println("robot is working");
}
@Override
public void eat() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("cannot eat");
}
}
要查看更完整的示例,请单击这里。
@Override
public void foo() {
//Not used: just needed to implement interface
}
这是一个实际在 PHP 中的应用示例。
问题陈述:
我想要为不同形式的内容添加评论和讨论。内容可以是任何形式,如论坛主题、新闻文章、用户档案,或是对话式私信。
架构
我们需要一个可重用的 DiscussionManager
类,将 Discussion
附加到特定的内容实体上。然而,以上四个示例(以及更多)都有其独特的概念差异。如果我们希望 DiscussionManager
使用它们,则所有四个(或更多)示例都需要具有一种共同的接口,以确保它们之间兼容。否则,DiscussionManager
将无法使用它们,除非您想使用裸参数(例如没有类型检查)。
解决方案:定义 Discussable
接口,其中包含以下方法:
attachDiscussion($topic_id)
detachDiscussion()
getDiscussionID()
然后,DiscussionManager
可能会像这样:
class DiscussionManager
{
public function addDiscussionToContent(Discussable $Content)
{
$Discussion = $this->DiscussionFactory->make( ...some data...);
$Discussion->save() // Or $this->DiscussionRepository->save($Discussion);
$Content->attachDiscussion($Discussion->getID()); // Maybe saves itself, or you can save through a repository
}
public function deleteDiscussion(Discussable $Content)
{
$id = $Content->getDiscussionID();
$Content->detatchDiscussion();
$this->DiscussionRepository->delete($id);
}
public function closeDiscussion($discussion_id) { ... }
}
这样,DiscussionManager
就不会关心它使用的各种内容类型的任何不相关行为。它只关心它需要的行为,而不管这些行为与什么相关联。因此,通过为您想要进行讨论的每种内容类型提供一个 Discussable
接口,您正在使用接口隔离原则。
这也是抽象基类不是一个好主意的好例子。论坛主题、用户资料和新闻文章在概念上甚至都不相同,因此试图让它们继承讨论行为会导致与不相关的父级产生奇怪的耦合。使用代表讨论的特定接口,您可以确保您想要进行讨论的实体与将管理这些讨论的客户端代码兼容。
对于 PHP 来说,这个例子也可能是 Traits 的一个很好的使用候选。