- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
引用以下链接:
http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html?page=2
The composition approach to code reuse provides stronger encapsulation than inheritance, because a change to a back-end class needn't break any code that relies only on the front-end class. For example, changing the return type of Fruit's peel() method from the previous example doesn't force a change in Apple's interface and therefore needn't break Example2's code.
当然,如果您更改 peel()
的返回类型(参见下面的代码),这意味着 getPeelCount()
将无法返回 int
还有吗?难道你不必更改接口(interface),否则会出现编译器错误吗?
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple {
private Fruit fruit = new Fruit();
public int peel() {
return fruit.peel();
}
}
class Example2 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
最佳答案
有了composition,改变类Fruit
并不一定需要改变Apple
,例如,让我们改变剥离
以返回 double
:
class Fruit {
// Return String number of pieces of peel that
// resulted from the peeling activity.
public double peel() {
System.out.println("Peeling is appealing.");
return 1.0;
}
}
现在,类 Apple
将警告精度丢失,但您的 Example2
类会很好,因为组合更“松散”并且发生变化在组合元素中不会破坏组合类 API。在我们的示例中,只需像这样更改 Apple
:
class Apple {
private Fruit fruit = new Fruit();
public int peel() {
return (int) fruit.peel();
}
}
而如果 Apple
inherited from Fruit
(class Apple extends Fruit
),你不仅会得到一个关于不兼容的返回类型方法的错误,但在 Example2
中也会出现编译错误。
** 编辑 **
让我们重新开始,给出一个组合与继承的“真实世界”示例。请注意,合成不限于此示例,还有更多可以使用该模式的用例。
应用程序将形状绘制到 Canvas 中。应用程序不需要知道它必须绘制哪些形状,并且实现在于继承抽象类或接口(interface)的具体类。但是,应用程序知道它可以创建什么以及可以创建多少种不同的具体形状,因此添加或删除具体形状需要在应用程序中进行一些重构。
interface Shape {
public void draw(Graphics g);
}
class Box implement Shape {
...
public void draw(Graphics g) { ... }
}
class Ellipse implements Shape {
...
public void draw(Graphics g) { ... }
}
class ShapeCanvas extends JPanel {
private List<Shape> shapes;
...
protected void paintComponent(Graphics g) {
for (Shape s : shapes) { s.draw(g); }
}
}
应用程序正在使用 native 库来处理某些数据。实际的库实现可能是已知的,也可能是未知的,并且将来可能会或可能不会改变。因此创建了一个公共(public)接口(interface),并在运行时确定了实际的实现。例如:
interface DataProcessorAdapter {
...
public Result process(Data data);
}
class DataProcessor {
private DataProcessorAdapter adapter;
public DataProcessor() {
try {
adapter = DataProcessorManager.createAdapter();
} catch (Exception e) {
throw new RuntimeException("Could not load processor adapter");
}
}
public Object process(Object data) {
return adapter.process(data);
}
}
static class DataProcessorManager {
static public DataProcessorAdapter createAdapter() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
String adapterClassName = /* load class name from resource bundle */;
Class<?> adapterClass = Class.forName(adapterClassName);
DataProcessorAdapter adapter = (DataProcessorAdapter) adapterClass.newInstance();
//...
return adapter;
}
}
因此,如您所见,组合可能比继承提供一些优势,因为它允许代码具有更大的灵 active 。它允许应用程序拥有可靠的 API,而底层实现在其生命周期内仍可能发生变化。如果使用得当,组合物可以显着降低维护成本。
例如,当使用 JUnit 为 示例 2 实现测试用例时,您可能希望使用虚拟处理器并设置 DataProcessorManager
以返回此类适配器,同时使用生产中的“真实”适配器(可能取决于操作系统),而无需更改应用程序源代码。使用继承,你很可能会修改一些东西,或者可能会编写更多的初始化测试代码。
如您所见,compisition 和 inheritance 在许多方面都不同,并且并不优于其他方面;每个都取决于手头的问题。你甚至可以混合继承和组合,例如:
static interface IShape {
public void draw(Graphics g);
}
static class Shape implements IShape {
private IShape shape;
public Shape(Class<? extends IShape> shape) throws InstantiationException, IllegalAccessException {
this.shape = (IShape) shape.newInstance();
}
public void draw(Graphics g) {
System.out.print("Drawing shape : ");
shape.draw(g);
}
}
static class Box implements IShape {
@Override
public void draw(Graphics g) {
System.out.println("Box");
}
}
static class Ellipse implements IShape {
@Override
public void draw(Graphics g) {
System.out.println("Ellipse");
}
}
static public void main(String...args) throws InstantiationException, IllegalAccessException {
IShape box = new Shape(Box.class);
IShape ellipse = new Shape(Ellipse.class);
box.draw(null);
ellipse.draw(null);
}
当然,最后一个例子并不干净(意思是,避免它),但它展示了如何使用组合。
底线是,DataProcessor
和 Shape
这两个示例都是“实体”类,它们的 API 不应更改。但是,适配器类可能会更改,如果发生更改,这些更改只会影响其组成容器,因此将维护限制在仅这些类而不是整个应用程序上,这与 示例 1 的任何更改相反需要在整个应用程序中进行更多更改。这完全取决于您的应用程序需要有多灵活。
关于oop - 作文,我不太明白?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9559291/
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 4年前关闭。 Improve t
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
在面向对象的编程中,“基类”是派生其他类的类(http://en.wikipedia.org/wiki/Base_class)。 但是,基类的反面是什么?换句话说,什么是没有任何子类的类? 编辑:我正
关闭。这个问题需要更多focused .它目前不接受答案。 想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post . 8年前关闭。 Improve this questi
据我了解,OOP 是大型项目最常用的范式。我也知道大系统的一些较小的子集使用其他范式(例如 SQL,它是声明性的),并且我也意识到在较低级别的计算 OOP 并不真正可行。但在我看来,通常更高级别的解决
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
最近听说OOP(Java)有9条规则。我只知道四种:抽象、多态、继承和封装。 OOP 还有更多规则吗? 最佳答案 看来您正在寻找的是 Principles of Object-Oriented Des
我曾经在一次采访中被问到“OOP 的 3 个主要概念是什么?”。我回答说,我认为有4个,如下: 继承 封装 抽象 多态性 我说得对吗? 最佳答案 语言要成为面向对象有3个要求: 仅支持封装(对象)的语
我有一个关于特定 OOP 问题的组织的简单问题。 假设我有一个地形类,里面充满了瓷砖。 Tile 类有多个派生类,即 Door。 Door 类有一个名为 open() 的方法,用于打开门,还有一个名为
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
我是 Go 的新手,然后我通过示例搜索了很多如何拥有带有静态函数/变量的静态类,例如 C#。但是,我找不到任何可以很好地回答它的东西。也许这个问题看起来很愚蠢,但我不喜欢不确定或不完全理解某事。 假设
我曾尝试搜索此问题的答案,但很难用语言表达,而且许多问题要么是关于如何创建类,要么是关于如何做非常具体的事情。我需要更多的实用概述 - 我是自学成才的,我了解对象是什么(以及如何创建它们),但我从未见
在开始编码之前,我通常会尝试在没有太多分析(没有图表)的情况下进行 TDD。通常我发现自己将一个类拆分为其他类以分离关注点。我想知道更深入的分析是否会阻止这种情况。我认为大部分面向对象分析无法预测其中
在阅读单例时,我发现这个解释是使用单例的原因: since these object methods are not changing the internal class state, we can
如这里所述 https://standardofnorms.wordpress.com/2012/09/02/4-pillars-of-object-oriented-programming/ 并作为
我是这个网站的新手,所以如果我在发布问题时做错了什么,请告诉我,以便我下次修复。 我很好奇从单个基类继承多个类是否是糟糕的 OOP 实践。这可能不太合理,所以我要详细说明一下。 例如,假设您正在设计一
我对“工厂相关”设计模式及其 OOP 实现的理解一直很简单。 一个 《工厂法》是类内部的一个方法,它有一个接口(interface)(或抽象类)作为返回类型,并根据一些内部逻辑构造实现该接口(inte
C# 中的“密封”关键字,Java 中的 Final。 因为我几乎从不创建任何图表并且我只使用已经完成的类(来自框架)我多年后仍然不知道为什么有人会“锁定”一个类所以它永远不会被扩展/继承。 它是有益
我正在研究面向对象的概念,抽象概念基本上被描述为对用户隐藏实现。因此,如果类中有一个成员函数并且我们为某些任务调用该函数,抽象表示用户不应该关心事情是如何完成的,而应该只知道正在完成什么。但即使在非面
我是一名优秀的程序员,十分优秀!