叶在综合模式实现了Component接口,包括Add,Remove,和GetChild方法,一个叶是永远不会使用.这似乎违反了接口隔离原则.
那么复合模式SOLID的用法是什么?
链接到Composite Pattern:http://www.dofactory.com/Patterns/PatternComposite.aspx
design-patterns liskov-substitution-principle composite solid-principles interface-segregation-principle
LSP说"派生类型不能改变基类型的行为",换言之,"派生类型必须完全可替换它们的基类型".
这意味着如果我们在基类中定义虚方法,我们就违反了这个原则.
此外,如果我们使用new关键字在驱动方法中隐藏方法,那么我们又违反了这个原则.
换句话说,如果我们使用多态,我们就违反了LSP!
在许多应用程序中,我在基类中使用了虚方法,现在我意识到它违反了LSP.此外,如果你使用模板方法模式,你违反了这个原则,我已经使用了很多.
那么,当你需要继承并且你也想从多态中受益时,如何设计符合这个原则的应用程序呢?我糊涂了!
请参阅此处的示例:http://www.oodesign.com/liskov-s-substitution-principle.html
c# polymorphism liskov-substitution-principle solid-principles
有人可以解释一下Refused Bequest的含义吗?我尝试阅读一些文章,并说它是一种代码气味,或者在wiki中它告诉它它是一个类,它覆盖基类的方法,使得基类的契约不受派生类的尊重.
但简而言之,或者更简单的说法,实际上是什么?
我总是在这个覆盖的站点中看到建议,getPreferredSize() 而不是setPreferredSize() 像以前的这些线程中所示那样使用.
看这个例子:
public class MyPanel extends JPanel{
private final Dimension dim = new Dimension(500,500);
@Override
public Dimension getPreferredSize(){
return new Dimension(dim);
}
public static void main(String args[]){
JComponent component = new MyPanel();
component.setPreferredSize(new Dimension(400,400));
System.out.println(component.getPreferredSize());
}
}
Run Code Online (Sandbox Code Playgroud)
setPreferredSize()
- 设置此组件的首选大小.
getPreferredSize()
- 如果preferredSize已设置为非null值,则返回它.如果UI委托的getPreferredSize方法返回非null值,则返回该值; 否则遵从组件的布局管理器.
所以这样做显然打破了Liskov替代原则.
prefferedSize是一个绑定属性,所以当你设置它时firePropertyChange执行.所以我的问题是,当你覆盖时,getPrefferedSize()你不需要覆盖setPreferredSize(..)吗?
例:
public class MyPanel extends JPanel{
private Dimension dim = null;
@Override
public Dimension …Run Code Online (Sandbox Code Playgroud) 今天有人告诉我,C#中的接口实现只是"Can-Do"关系,而不是"Is-A"关系.这与我长期相信LSP(Liskov Substitution Principle)相冲突.我一直认为所有的继承都应该意味着"Is-A"的关系.
所以,如果接口实现只是一个"可以做"的关系.如果有一个界面"IHuman"和"IEngineer",并且一个类"Programmer"继承自"IHuman"和"IEngineer"怎么办?当然,"程序员"是"IHuman"和"IEngineer".
如果只是"Can-Do"关系,是否意味着我们不能指望"程序员"实例行为在被视为IHuman并被视为IEngineer时可能会有所不同?
假设我有这样一个类:
public sealed class Foo
{
public void Bar
{
// Do Bar Stuff
}
}
Run Code Online (Sandbox Code Playgroud)
我想扩展它以添加超出扩展方法可以做的事情....我唯一的选择是组合:
public class SuperFoo
{
private Foo _internalFoo;
public SuperFoo()
{
_internalFoo = new Foo();
}
public void Bar()
{
_internalFoo.Bar();
}
public void Baz()
{
// Do Baz Stuff
}
}
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但它还有很多工作......但是我仍遇到一个问题:
public void AcceptsAFoo(Foo a)
Run Code Online (Sandbox Code Playgroud)
我可以在这里传递一个Foo,但不是超级Foo,因为C#不知道SuperFoo确实符合Liskov替换意义......这意味着我的扩展类通过组合使用非常有限.
因此,解决它的唯一方法是希望原始的API设计者留下一个界面:
public interface IFoo
{
public Bar();
}
public sealed class Foo : IFoo
{
// etc
}
Run Code Online (Sandbox Code Playgroud)
现在,我可以在SuperFoo上实现IFoo(因为SuperFoo已经实现了Foo,只需要更改签名).
public class SuperFoo : IFoo
Run Code Online (Sandbox Code Playgroud)
在完美的世界中,消耗Foo的方法将消耗IFoo:
public …Run Code Online (Sandbox Code Playgroud) 适配器设计模式用于将类(Target)的接口转换为客户期望的另一个接口(Adaptee).适配器允许不兼容的类一起工作,否则由于它们的不兼容接口而无法工作.
适配器模式可以通过两种方式实现:继承(适配器模式的类版本)和组合(适配器模式的对象版本).
我的问题是关于使用继承实现的适配器模式的类版本.
以下是绘图编辑器的示例:

interface Shape
{
Rectangle BoundingBox();
Manipulator CreateManipulator();
}
class TextView
{
public TextView() { }
public Point GetOrigin() { }
public int GetWidth() { }
public int GetHeight() { }
}
interface Shape
{
Rectangle BoundingBox();
Manipulator CreateManipulator();
}
class TextView
{
public TextView() { }
public Point GetOrigin() { }
public int GetWidth() { }
public int GetHeight() { }
}
Run Code Online (Sandbox Code Playgroud)
我们想重用TextView类来实现TextShape,但是接口是不同的,因此,TextView和Shape对象不能互换使用.
是否应该更改TextView类以符合形状界面?也许不是.
TextShape可以通过以下两种方式之一使TextView接口适应形状的界面:
类适配器

interface Shape
{
Rectangle BoundingBox();
Manipulator …Run Code Online (Sandbox Code Playgroud) design-patterns liskov-substitution-principle adapter solid-principles
子类型的实际前提是通过(使用逻辑组合创建的OR)的基类型的先决条件和亚型的先决条件,这使得所得的先决条件 的限制较少
子类型的实际后置条件是通过(使用逻辑组合创建的AND)碱型的后置和一个亚型的后置条件,这使得所得的后置条件 更严格的
以下是加强前提条件和弱化后置条件的例子,因此违反了LSP(Link):
假设您的基类使用成员int.现在你的子类型要求int为正数.这是强化前置条件,现在任何在使用负数之前完全正常工作的代码都会被破坏.
同样,假设相同的场景,但基类用于保证成员在被调用后是正面的.然后子类型更改行为以允许负的int.由于不支持后置条件,因此对该对象起作用的代码(并假设后置条件为正int)现在已被破坏.
a)当重写方法削弱前提条件时,为什么它也不被视为违反LSP ,因为此方法可以使用基类型合约不可接受的参数.因此,我们不能声称违反了基本类型的合同,因此LSP也被违反了吗?
乙)为什么是不是也认为是违反LSP时覆盖的方法加强后置条件,因为客户端调用此方法将只接收的原始方法的可能结果的一个子集.因此,我们不能声称违反了基本类型的合同,因此LSP也被违反了吗?
例:
基类后置条件保证方法的返回值在范围内1-10,但子类型将后置条件更改为仅允许返回值在范围内2-9.现在,由于不支持后置条件,因此破坏了从此方法返回的对象的代码(并假设后置条件在一个范围内1-10).
inheritance liskov-substitution-principle preconditions post-conditions
是否存在无法编写或寻求的Stream派生类的事实是否打破了Liskov替换原则?
例如,无法搜索NetworkStream,NotSupportedException如果Seek调用该方法,它将抛出一个.
或者因为CanSeek旗帜的存在可以吗?
鉴于众所周知的例子Square继承Rectangle......会标志的加入DoesHeightAffectsWidth,并DoesWidthAffectsHeight以Rectangle解决这个问题?
这不是通过添加标志来打开固定东西的大门吗?
c# oop liskov-substitution-principle stream solid-principles
我想将数据与数据源分开.一个用于数据库交互的类和用于数据操作的类.但是我的方法违反了LSP:preconditions cannot be strengthened in a subtype 并引发了严格的错误:Declaration of DataRepositoryItem::save() should be compatible with DataRepositoryAbstract::save(DataAbstract $data)
class DataAbstract {
}
class DataItem extends DataAbstract {
}
class DataObject extends DataAbstract {
}
abstract class DataRepositoryAbstract {
/** @return DataAbstract */
public function loadOne(){}
/** @return DataAbstract[] */
public function loadAll(){}
public function save(DataAbstract $data){}
}
class DataRepositoryItem extends DataRepositoryAbstract {
/** @return DataItem */
public function loadOne(){}
/** @return DataItem[] */
public function loadAll(){}
public function …Run Code Online (Sandbox Code Playgroud) php oop inheritance liskov-substitution-principle solid-principles
liskov-substitution-principle ×10
c# ×4
inheritance ×3
oop ×2
.net ×1
adapter ×1
composite ×1
composition ×1
duck-typing ×1
interface ×1
interface-segregation-principle ×1
java ×1
jcomponent ×1
php ×1
polymorphism ×1
stream ×1
swing ×1